9

我有一个从 TMemo 派生的控件。在我第一次使用 Delphi XE7 VCL Styles 之前,它一直很好用。在 Delphi XE7 下,样式不会应用于控件的滚动条。如果使用深色主题/样式,它看起来很可怕,而滚动条是银色的。

漏洞

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

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

源代码在这里:

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

4

1 回答 1

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存储方式所致。它们存储在 key 所在的字典中TClass。顺序由TClass散列决定,散列基本上是指向类信息的指针,并且可以随着您更改代码而更改。

问题报告为RSP-10066,并且附有复制它的项目。

在以下代码的帮助下,很容易看到注册类的顺序在您添加/删除代码和/或其他控件时如何变化。

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;
于 2015-02-12T09:22:35.827 回答