TEdit 和WM_PAINT消息处理程序的奇怪行为



TEdit控件没有焦点时,我正在尝试在控件上实现自己的绘图(当编辑器未完全显示其文本时,TEdit显示省略号)。所以我用这个代码盯着:

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 and (not Focused)时,消息处理程序不执行任何操作。

现在我在窗体上删除了一个TButton和 2 个 TEdit 控件,并添加了窗体OnCreate

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

我希望Edit1正常绘制,并且Edit2不会在编辑控件内绘制任何内容。

相反,消息处理程序被无休止地处理,Edit1也没有被绘制,整个应用程序都窒息了(CPU 使用率为 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;

请注意,我也没有打电话给inherited

如何解释这种行为?谢谢。

当窗口失效时,会要求它在下一个绘制周期中使其有效。通常,当GetMessage发现队列为空时,这会在主线程消息循环中发生。此时WM_PAINT消息被合成并调度到窗口。

当窗口收到这些消息时,它的任务是绘制自己。这通常是通过调用BeginPaint然后EndPaint来完成的。对BeginPaint的调用将验证窗口的客户端 rect。这是您缺少的关键信息。

现在,在您的代码中,您没有调用inherited,因此没有绘制任何内容,也没有调用BeginPaint/EndPaint.因为您没有调用BeginPaint ,所以窗口仍然无效。因此,生成了源源不断的WM_PAINT消息。

相关文档可在此处找到:

BeginPaint 函数会自动验证整个工作区。

相关内容

  • 没有找到相关文章

最新更新