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に登録されているもの)、代わりにそれを使用します。スクロールバーの問題を処理する方法がわからないため、表示されます 。TCustomEditTMemoStyleHookTEditStyleHook

バグのある動作のランダム性は、RegisteredStyleHooks保存方法によるものです。それらは、キーが である辞書に格納されます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 に答える