TEdit and WM_PAINT behavior strange behavior

I am trying to implement my own drawing on a TEdit control when it has no focus (show the ellipsis in TEdit when the editor does not fully display its text). So I start with this code:

 type TEdit = class(StdCtrls.TEdit) private FEllipsis: Boolean; FCanvas: TCanvas; procedure WMPaint(var Message: TWMPaint); message WM_PAINT; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; constructor TEdit.Create(AOwner: TComponent); begin inherited Create(AOwner); FEllipsis := False; FCanvas := TControlCanvas.Create; TControlCanvas(FCanvas).Control := Self; end; destructor TEdit.Destroy; begin FCanvas.Free; inherited; end; procedure TEdit.WMPaint(var Message: TWMPaint); begin if FEllipsis and (not Focused) then begin // Message.Result := 0; // TODO... end else inherited; end; 

Note that when FEllipsis and (not Focused) the message handler does nothing.

Now I have reset the TButton and 2 TEdit in the form and added the OnCreate form:

 procedure TForm1.FormCreate(Sender: TObject); begin Edit2.FEllipsis := True; end; 

I was expecting Edit1 to draw normally, and Edit2 would not draw anything inside the edit control.

Instead, the message handler was processed endlessly, Edit1 also not drawn, and the entire application was suffocating (with 25% CPU usage!). I also tried returning Message.Result := 0 - the same effect.

Now, for the “weird” part: when I get the canvas handle with BeginPaint , everything works as expected.

 procedure TEdit.WMPaint(var Message: TWMPaint); var PS: TPaintStruct; begin if FEllipsis and (not Focused) then begin if Message.DC = 0 then FCanvas.Handle := BeginPaint(Handle, PS) else FCanvas.Handle := Message.DC; try // paint on FCanvas... finally FCanvas.Handle := 0; if Message.DC = 0 then EndPaint(Handle, PS); end; end else inherited; end; 

Note that I did not invoke inherited .

How to explain this behavior? Thanks.

+8
delphi vcl editcontrol
source share
1 answer

When a window is invalid, it is asked to be valid in the next paint cycle. This usually happens in the main thread's message loop when GetMessage detects that the queue is empty. At this point, WM_PAINT messages are synthesized and sent to the window.

When a window receives these messages, its task is to draw. This is usually done with calls to BeginPaint and then to EndPaint . Calling BeginPaint checks the client window is correct. This is a critical piece of information that you lack.

Now in your code you did not call inherited and therefore did not draw anything and did not call BeginPaint / EndPaint . Since you did not call BeginPaint , the window remains invalid. And so an endless stream of WM_PAINT messages is created.

The relevant documentation can be found here :

The BeginPaint function automatically checks the entire client area.

+13
source share

All Articles