首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >自动调整TCheckBox的大小(如TLabel)

自动调整TCheckBox的大小(如TLabel)
EN

Stack Overflow用户
提问于 2019-11-29 15:11:20
回答 1查看 927关注 0票数 4

我想要创建一个复选框,它可以自动调整其宽度,就像TLabel一样。

代码语言:javascript
运行
复制
UNIT cvCheckBox;
{  It incercepts CMTextChanged where it recomputes the new Width}
INTERFACE
USES
  Winapi.Windows, Winapi.Messages, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.StdCtrls;

TYPE
 TcCheckBox = class(TCheckBox)
 private
   FAutoSize: Boolean;
   procedure AdjustBounds;
   procedure setAutoSize(b: Boolean);  reintroduce;
   procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
   procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
 protected
    procedure Loaded; override;
 public
    constructor Create(AOwner: TComponent); override;
 published
    //property Caption read GetText write SetText;
    property AutoSize: Boolean read FAutoSize write setAutoSize stored TRUE;
 end;

IMPLEMENTATION

CONST
  SysCheckWidth: Integer = 21;  // In theory this can be obtained from the "system"

constructor TcCheckBox.Create(AOwner : TComponent);
begin
  inherited Create(AOwner);
  FAutoSize:= TRUE;
end;


procedure TcCheckBox.AdjustBounds;
VAR
   DC: HDC;
   Canvas: TCanvas;
begin
  if not (csReading in ComponentState) and FAutoSize then
  begin
    // this caused the problem [solution provided by Dima] 
    if HandleAllocated then   // Deals with the missing parent during Creation
    begin
     // We need a canvas but this control has none. So we need to "produce" one.
     Canvas := TCanvas.Create;
     DC     := GetDC(Handle);
     TRY
       Canvas.Handle := DC;
       Canvas.Font   := Font;
       Width := Canvas.TextWidth(Caption) + SysCheckWidth + 4;
       Canvas.Handle := 0;
     FINALLY
       ReleaseDC(Handle, DC);
       Canvas.Free;
     END;
    end;
  end;
end;


procedure TcCheckBox.setAutoSize(b: Boolean);
begin
  if FAutoSize <> b then
  begin
    FAutoSize := b;
    if b then AdjustBounds;
  end;
end;

procedure TcCheckBox.CMTextChanged(var Message:TMessage);
begin
  Invalidate;
  AdjustBounds;
end;


procedure TcCheckBox.CMFontChanged(var Message:TMessage);
begin
  inherited;
  if AutoSize
  then AdjustBounds;
end;

procedure TcCheckBox.Loaded;
begin
  inherited Loaded;
  AdjustBounds;
end;
end.

但我有个问题。放在PageControl的非活动选项卡中的复选框不会自动重新计算它们的大小。换句话说,如果我有两个包含复选框的选项卡,在应用程序启动时,只有当前打开选项卡中的复选框才能正确调整大小。当我单击另一个选项卡时,复选框将具有原始大小(在设计时设置的一个)。

在程序启动时,我确实设置了整个表单的字体大小(在表单创建之后,使用PostMessage(Self.Handle,MSG_LateInitialize) )。

代码语言:javascript
运行
复制
procedure TForm5.FormCreate(Sender: TObject);
begin
 PostMessage(Self.Handle, MSG_LateInitialize, 0, 0);  
end;

procedure TForm5.LateInitialize(var message: TMessage);
begin
 Font:= 22;
end;

为什么“非活动”选项卡中的复选框没有宣布字体已更改?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-29 18:42:36

正如我在对这个问题的评论中指出的,问题在于TPageControl只初始化了当前选择的页面。这意味着另一个页面将没有有效的句柄。因此,放置在它们上的所有组件也没有句柄。这是AdjustBounds方法根本无法工作的原因。

但是,通过使用常量DeviceContext以其他方式获取HWND_DESKTOP,可以解决这种糟糕的情况(有关详细信息,请参阅更新部分)。

见下面的代码:

代码语言:javascript
运行
复制
procedure TcCheckBox.AdjustBounds;
var
  DC: HDC;
  Canvas: TCanvas;
begin
  if not (csReading in ComponentState) and FAutoSize then
  begin
    // Retrieve DC for the entire screen
    DC := GetDC(HWND_DESKTOP);
    try
      // We need a canvas but this control has none. So we need to "produce" one.
      Canvas := TCanvas.Create;
      try
        Canvas.Handle := DC;
        Canvas.Font := Font;
        Width := Canvas.TextWidth(Caption) + SysCheckWidth + 4;
        Canvas.Handle := 0;
      finally
        Canvas.Free;
      end;
    finally
      ReleaseDC(HWND_DESKTOP, DC);
    end;
  end;
end;

更新

由于已经发布了一些有用的注释,所以我更改了代码以消除对GetDesktopWindow函数的调用。相反,代码使用传递给GetDC函数的GetDC常量,允许获得整个屏幕的DeviceContext

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59107255

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档