VCL样式随机打破

时间:2015-02-11 20:09:56

标签: delphi delphi-xe7 vcl-styles

我有一个源自TMemo的控件。在我第一次使用Delphi XE7 VCL样式之前,它工作得很好。在Delphi XE7下,样式不会应用于控件的滚动条。如果使用黑暗的主题/风格,它看起来很可怕,而滚动条是银色的。

bug

尝试创建一个我们可以重现错误的最小项目我发现了一些非常有趣的东西:添加/删除随机代码行(或DFM控件)会使错误出现/消失。

问题:究竟是什么导致了这种奇怪的行为以及如何解决这个问题?

源代码:

http://s000.tinyupload.com/index.php?file_id=24129853712119260018

1 个答案:

答案 0 :(得分:7)

为自定义类解决问题注册StyleHook

  TMyMemo = class(TMemo)
  strict private
    class constructor Create;
    class destructor Destroy;
  end;

class constructor TMyMemo.Create;
begin
  TCustomStyleEngine.RegisterStyleHook(TMyMemo, TMemoStyleHook);
end;

class destructor TMyMemo.Destroy;
begin
  TCustomStyleEngine.UnRegisterStyleHook(TMyMemo, TMemoStyleHook);
end;

TStyleEngine.HandleMessage函数中存在错误,特别是部分试图找到合适的StyleHook类来处理消息

if RegisteredStyleHooks.ContainsKey(Control.ClassType) then
  // The easy way: The class is registered
  LStyleHook := CreateStyleHook(RegisteredStyleHooks[Control.ClassType])
else
begin
  // The hard way: An ancestor is registered
  for LItem in RegisteredStyleHooks do
    if Control.InheritsFrom(LItem.Key) then
    begin
      LStyleHook := CreateStyleHook(Litem.Value);
      Break;
    end;

如果StyleHook注册了确切的类,则没有问题,并且将返回适当的StyleHook类。然而,“艰难的方式”部分是有缺陷的。它将尝试查找已注册StyleHook的类祖先。但它会回归它所遇到的第一个祖先。如果它首先找到TEditStyleHook(已注册TCustomEdit类),则会使用该TMemoStyleHook而不是TEditStyleHook。由于RegisteredStyleHooks不知道如何处理滚动条问题。

有缺陷行为的随机性是由TClass存储的方式决定的。它们存储在密钥为TClass的字典中。并且顺序由type TStyleHelper = class(TCustomStyleEngine) public class function GetClasses: TArray<TClass>; end; class function TStyleHelper.GetClasses: TArray<TClass>; begin Result := Self.RegisteredStyleHooks.Keys.ToArray; end; procedure TForm1.Button1Click(Sender: TObject); var LItem: TClass; Classes: TArray<TClass>; begin Classes := TStyleHelper.GetClasses; for LItem in Classes do MyMemo1.Lines.Add(LItem.ClassName); end; 哈希确定,该哈希基本上是指向类信息的指针,并且可以在您更改代码时更改。

问题报告为RSP-10066,并且附加项目可以重现它。

借助以下代码,您可以轻松查看在添加/删除代码和/或其他控件时注册类的顺序如何变化。

{{1}}