一段时间后 TToolbar 停止显示按钮标题

TToolbar stops displaying button captions after a while

知道为什么带有 TToolButtons 的 TToolbar 会在一段时间后停止显示按钮标题吗?这发生在整个应用程序 auto-created 窗体上的所有工具栏上。即使出现此问题,动态创建的表单上的工具栏也能正常工作。

我只在一台 Windows 7 笔记本电脑上看到过这种情况。发生这种情况时不会出现任何错误,而且我无法根据命令重现该问题。唯一的解决办法是重新启动应用程序。

TToolbar.ShowCaptions 始终为 True 且从未更改。这在下图中也可见,因为当 ShowCaptions 为 False 时图标垂直对齐。

以前在 Windows 8 PC 上也发生过类似的问题。但是这次字幕被替换为其他文字。

编辑:

我能够通过在 5-10k 次之间调用 TImageList.Change 来重现该问题。我只有 Delphi 2010,所以我不能说这是 Delphi 还是 Windows 问题。

单位:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ImgList, ComCtrls, ToolWin, StdCtrls, Gauges;

type
  TImageListHelper = class helper for TImageList
  public
    procedure DoChange;
  end;

  TForm1 = class(TForm)
    ToolBar1: TToolBar;
    ToolButton1: TToolButton;
    ToolButton2: TToolButton;
    ToolButton3: TToolButton;
    ToolButton4: TToolButton;
    ToolButton5: TToolButton;
    ToolButton6: TToolButton;
    ToolButton7: TToolButton;
    ToolButton8: TToolButton;
    ToolButton9: TToolButton;
    ToolButton10: TToolButton;
    ImageList1: TImageList;
    ProgressBar1: TProgressBar;
    procedure ToolButton1Click(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ToolButton1Click(Sender: TObject);
begin
  repeat
    ImageList1.DoChange;
    ProgressBar1.StepIt;
    Self.Update;
  until ProgressBar1.Position >= ProgressBar1.Max;
end;

procedure TImageListHelper.DoChange;
begin
  Self.Change;
end;

end.

表格:

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 66
  ClientWidth = 711
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  PixelsPerInch = 96
  TextHeight = 13
  object ToolBar1: TToolBar
    Left = 0
    Top = 0
    Width = 711
    Height = 41
    ButtonHeight = 36
    ButtonWidth = 71
    Caption = 'ToolBar1'
    Images = ImageList1
    ShowCaptions = True
    TabOrder = 0
    ExplicitWidth = 885
    object ToolButton1: TToolButton
      Left = 0
      Top = 0
      Caption = 'ToolButton1'
      ImageIndex = 0
      OnClick = ToolButton1Click
    end
    object ToolButton2: TToolButton
      Left = 71
      Top = 0
      Caption = 'ToolButton2'
      ImageIndex = 0
    end
    object ToolButton3: TToolButton
      Left = 142
      Top = 0
      Caption = 'ToolButton3'
      ImageIndex = 0
    end
    object ToolButton4: TToolButton
      Left = 213
      Top = 0
      Caption = 'ToolButton4'
      ImageIndex = 0
    end
    object ToolButton5: TToolButton
      Left = 284
      Top = 0
      Caption = 'ToolButton5'
      ImageIndex = 0
    end
    object ToolButton6: TToolButton
      Left = 355
      Top = 0
      Caption = 'ToolButton6'
      ImageIndex = 0
    end
    object ToolButton7: TToolButton
      Left = 426
      Top = 0
      Caption = 'ToolButton7'
      ImageIndex = 0
    end
    object ToolButton8: TToolButton
      Left = 497
      Top = 0
      Caption = 'ToolButton8'
      ImageIndex = 0
    end
    object ToolButton9: TToolButton
      Left = 568
      Top = 0
      Caption = 'ToolButton9'
      ImageIndex = 0
    end
    object ToolButton10: TToolButton
      Left = 639
      Top = 0
      Caption = 'ToolButton10'
      ImageIndex = 0
    end
  end
  object ProgressBar1: TProgressBar
    Left = 0
    Top = 49
    Width = 711
    Height = 17
    Align = alBottom
    Max = 10000
    Step = 1
    TabOrder = 1
    ExplicitTop = 48
  end
  object ImageList1: TImageList
    Left = 8
    Top = 16
    Bitmap = {
      494C010101000500040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
      0000000000003600000028000000400000001000000001002000000000000010
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      FF000000FF000000000000000000000000000000000000000000000000000000
      FF000000FF000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      FF000000FF000000000000000000000000000000000000000000000000000000
      FF000000FF000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000FF000000FF0000000000000000000000FF000000FF000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000FF000000FF0000000000000000000000FF000000FF000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      00000000000000000000000000000000FF000000FF0000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      00000000000000000000000000000000FF000000FF0000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000FF000000FF0000000000000000000000FF000000FF000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000FF000000FF0000000000000000000000FF000000FF000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      FF000000FF000000000000000000000000000000000000000000000000000000
      FF000000FF000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      FF000000FF000000000000000000000000000000000000000000000000000000
      FF000000FF000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      0000000000000000000000000000000000000000000000000000000000000000
      000000000000000000000000000000000000424D3E000000000000003E000000
      2800000040000000100000000100010000000000800000000000000000000000
      000000000000000000000000FFFFFF00FFFF000000000000FFFF000000000000
      FFFF000000000000E7E7000000000000E7E7000000000000F99F000000000000
      F99F000000000000FE7F000000000000FE7F000000000000F99F000000000000
      F99F000000000000E7E7000000000000E7E7000000000000FFFF000000000000
      FFFF000000000000FFFF00000000000000000000000000000000000000000000
      000000000000}
  end
end

鉴于问题中的再现,我认为问题在于 VCL 工具栏代码删除了所有按钮,然后在修改图像列表时重新创建它们。

我正在查看 Delphi 6 代码,因为我手头没有 Delphi 2010,但代码没有实质性改变。相关代码在 TToolBar.CreateButtons 中。在这个方法的底部,我们有:

for I := 0 to InternalButtonCount - 1 do Perform(TB_DELETEBUTTON, 0, 0);
UpdateButtons;

循环删除所有按钮,然后 UpdateButtons 将它们添加回来。底层控件似乎不喜欢被这样对待。我们可以不删除所有按钮,而是只删除任何多余的按钮。

var
  Count: Integer;
....
Count := InternalButtonCount;
while Count>FButtons.Count do
begin
  Perform(TB_DELETEBUTTON, Count-1, 0);
  dec(Count);
end;
UpdateButtons;

在您的示例代码和实际应用程序中,您没有更改按钮的数量,因此此版本甚至没有进入循环。

通过此更改,您的程序可以正常运行。

您可以通过执行以下操作在您的应用程序中应用此更改:

  1. 从安装目录的源文件夹中复制 ComCtrls.pas,并将其保存在项目树中。
  2. 将复制的 ComCtrls 单元添加到您的项目中。
  3. 进行上述修改。

这似乎是 Delphi 2010 中 function TToolBar.UpdateItem() 末尾的 ComCtrls 单元中的错误。该函数从第 21476 行开始。

在 Delphi XE4 中(它可能早先已修复,我无法检查)以下注释和代码(Delphi 2010 中缺少)出现在 函数结束:

  // If more than 2^16 strings are TB_ADDSTRING-ed to the tool bar's string
  // pool, the Windows API assumes iString is a pointer to a null terminated
  // string, not an index in the string pool.  Therefore we have to recreate
  // the toolbar to reset the string pool so the strings display propperly.
  if Button.iString >= 65536 then
    RecreateWnd;

将 Delphi 2010 ComCtrls.pas 的副本复制到项目文件夹并添加以上代码,解决了您的测试产生的问题。