You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 11.3中TToolButton运行时文本强制左对齐的实现方案

解决Delphi 11.3中TToolBar垂直模式下TToolButton文本左对齐问题

在Delphi 11.3中使用垂直排列的TToolBar(开启文本模式)时,会遇到一个问题:设计阶段按钮文本是左对齐的,但运行时自动变为居中显示。要实现文本左对齐并紧贴图标,关键是修改TToolBarStyleHook中计算文本区域的逻辑。

你找到的Vcl.ComCtrls单元中TToolBarStyleHook.Paint方法代码里,计算文本尺寸时用了DT_CENTER or DT_WORDBREAK or DT_CALCRECT,随后调用RectCenter(sRect, R)把文本区域居中,这就是运行时文本偏移的根源——即使后续绘制文本用了DT_LEFT,也因为区域已经被居中导致视觉上还是偏右。

要解决这个问题,需要重写TToolBarStyleHook的Paint方法,将计算文本尺寸时的DT_CENTER替换为DT_LEFT,同时去掉RectCenter(sRect, R)的调用(因为不需要再居中区域)。具体步骤如下:

实现自定义StyleHook

创建一个单元,编写自定义的TToolBarStyleHook子类:

unit CustomToolBarStyleHook;

interface

uses
  Vcl.ComCtrls, Vcl.Styles.Utils.SysStyleHooks, Winapi.Messages, Winapi.Windows,
  Vcl.Controls, Vcl.Graphics, System.Classes, Vcl.Themes;

type
  TCustomToolBarStyleHook = class(TToolBarStyleHook)
  protected
    procedure Paint(Canvas: TCanvas); override;
  end;

implementation

uses
  Vcl.Styles.Utils.Graphics;

procedure TCustomToolBarStyleHook.Paint(Canvas: TCanvas);
var
  Details: TThemedElementDetails;
  ButtonState: TThemedToolBar;
  LStyle: TCustomStyleServices;
  R, sRect, iRect: TRect;
  Info: TToolButtonInfo;
  ImageDrawed: Boolean;
  DrawButtonFace: Boolean;
  WStyle: DWORD;
begin
  inherited;
  LStyle := StyleServices;
  if not LStyle.Available then Exit;

  Details := LStyle.GetElementDetails(tbButtonNormal);
  ButtonState := ttbButtonNormal;
  GetClientRect(Control.Handle, R);
  DrawButtonFace := True;

  if GetToolBarInfo(Control.Handle, Info) then
  begin
    WStyle := GetWindowLongPtr(Control.Handle, GWL_STYLE);
    if (WStyle and TBSTYLE_LIST = TBSTYLE_LIST) then
    begin
      sRect := R;
      Canvas.Font := TControlClass(Control).Font;
      // 将DT_CENTER改为DT_LEFT,不居中计算文本区域
      DrawText(Canvas.Handle, PChar(Info.pszText), Length(Info.pszText), sRect, DT_LEFT or DT_WORDBREAK or DT_CALCRECT);
      // 移除RectCenter调用,保持文本区域左对齐
      // RectCenter(sRect, R);
      ImageDrawed := False;
      if (Info.iImage >= 0) and (FImages <> nil) then
      begin
        iRect := Rect(5, iRect.Top, FImages.Width + 5, iRect.Bottom);
        OffsetRect(iRect, R.Left, 0);
        ImageDrawed := True;
        sRect := Rect(iRect.Right + 3, sRect.Top, R.Right, sRect.Bottom);
      end;
      if DrawButtonFace then
        DrawControlText(Canvas, Details, Info.pszText, sRect, DT_LEFT or DT_WORDBREAK)
      else
      begin
        if ButtonState <> ttbButtonDisabled then
          Canvas.Font.Color := LStyle.GetSystemColor(clBtnText)
        else
          Canvas.Font.Color := LStyle.GetSystemColor(clGrayText);
        SetBkMode(Canvas.Handle, Transparent);
        DrawText(Canvas.Handle, Info.pszText, Length(Info.pszText), sRect, DT_LEFT or DT_WORDBREAK);
      end;
    end;
  end;
end;

initialization
  // 替换TToolBar的默认StyleHook
  TCustomStyleEngine.RegisterStyleHook(TToolBar, TCustomToolBarStyleHook);

finalization
  // 注销自定义StyleHook
  TCustomStyleEngine.UnRegisterStyleHook(TToolBar, TCustomToolBarStyleHook);

end.

使用说明

  1. 将上述单元添加到项目中
  2. 在主窗体的uses列表中引用CustomToolBarStyleHook单元
  3. 运行程序后,垂直排列的TToolBar按钮文本会保持左对齐,紧贴图标

注意:代码中保留了原方法的核心逻辑,仅修改了文本区域计算的对齐方式和移除居中步骤,确保兼容性。

内容的提问来源于stack exchange,提问作者Bart Kindt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 17:33:09