我正在尝试在没有焦点的情况下在TEdit控件上实现我自己的绘图(当编辑器没有完全显示其文本时在TEdit中显示省略号).所以我用这段代码明星אed:
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;
请注意,当FEllipsis和(未聚焦)消息处理程序不执行任何操作时.
现在我在表单上删除了TButton和2个TEdit控件,并添加了OnCreate形式:
procedure TForm1.FormCreate(Sender: TObject); begin Edit2.FEllipsis := True; end;
我希望Edit1正常绘制,Edit2不要在编辑控件中绘制任何内容.
相反,消息处理程序被无休止地处理,Edit1也没有被绘制,整个应用程序都在窒息(占用率为25%!).我也尝试过返回Message.Result:= 0 – 效果相同.
现在,对于“奇怪”部分:当我使用BeginPaint获取画布句柄时,一切都按预期工作.
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;
注意我也没有调用继承.
如何解释这种行为?谢谢.
解决方法
当窗口无效时,要求它在下一个绘制周期中使其自身有效.通常,当GetMessage发现队列为空时,会在主线程消息循环中发生.此时,WM_PAINT消息被合成并分派到窗口.
当窗口收到这些消息时,它的任务是绘制自己.这通常是通过调用BeginPaint然后调用EndPaint来完成的.对BeginPaint的调用验证窗口的客户端rect.这是您缺乏的重要信息.
现在,在你的代码中,你没有调用inherited,所以没有绘制任何东西,也没有调用BeginPaint / EndPaint.因为您没有调用BeginPaint,所以窗口仍然无效.因此,生成了源源不断的WM_PAINT消息.
相关文档可以在here找到:
The BeginPaint function automatically validates the entire client area.