3

概要

TXPStyleMenuItem から継承するいくつかのプロシージャをオーバーライドしています。これは、TActionMainMenuBar を使用するときにメニューがどのように表示されるかを変更できるようにするためです。

例:

  TMyXPStyleMenuItem = class(TXPStyleMenuItem)
  protected
    procedure DrawBackground(var PaintRect: TRect); override;
  end;

TActionMainMenuBar から派生した独自のコンポーネントを作成し、GetControlClass メソッドで をvar ControlClass: TCustomActionControlClassTMyXPStyleMenuItem に設定しました。

これまでのところ、うまく機能していますが、明らかに上記の例よりも完全です-質問の目的のために、できるだけ短くシンプルに保ちました。

スタイラー コンポーネント

基本的に公開されたプロパティの集まりにすぎない非ビジュアル スタイラー コンポーネントを作成しました。このスタイラー コンポーネントは、いくつかのコントロールに割り当てることができます。この場合は、私の子孫の TActionMainMenuBar です。

コントロールにスタイラー コンポーネントが割り当てられている場合、コントロールはプロパティの値を読み取り、その値に基づいてペイントします。スタイラー コンポーネントが割り当てられていない場合は、デフォルトを使用してコントロールの描画方法を決定します。

簡単な例は、私のカスタム TEdit の 1 つです。割り当てられたスタイラー値に応じて色を変更できます。

TMyEdit = class(TCustomEdit)
private
  FStyler: TMyStyler;
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
end;

if Assigned(FStyler) then
begin
  Color := FStyler.Color;
end;

問題

私が直面している問題は、 のオーバーライドされた手順にありますTMyXPStyleMenuItem = class(TXPStyleMenuItem)

スタイラー コンポーネントの値を読み取る必要がありますが、TMyXPStyleMenuItem は実際にはメニュー コンポーネントの一部ではないため、どこFStylerから来たのか (たとえば、TActionMainMenuBar のどのインスタンスに割り当てられたのか)を知る方法がありません。

通常、FStyler は私のメニュー クラスから次のように設定されます。

private
  FStyler: TMyStyler;
  procedure SetStyler(const Value: TMyStyler);
published
  property Styler: TMyStyler read FStyler write SetStyler;

..

procedure TMyMenu.SetStyler(const Value: TMyStyler);
begin
  if Value <> FStyler  then
  begin
    FStyler := Value;
  end;
end;

しかし、からのそれらの手順TMyXPStyleMenuItemは上記について知りません。

宣言が基本クラスと異なるため機能しないため、オーバーライドされたプロシージャに新しいパラメーターを含めることはできません。例:

procedure DrawBackground(var PaintRect: TRect; AStyler: TMyStyler); override;

ほとんどありました

私が得た最も近いものは、実装部分の上にグローバル変数を作成したメニューコンポーネントのユニットでした:

var
  FStyler: TMyStyler;

implementation

次に、オーバーライドされた DrawBackground プロシージャで、次のようにしました。

procedure TMyXPStyleMenuItem.DrawBackground(var PaintRect: TRect);

  procedure _DrawBackground(AStyler: TMyStyler);
  begin
    // handle all the painting from here
    // using the values from AStyler.
  end;

begin
  if Assigned(FStyler) then
    _DrawBackground(FStyler);
end;

動作していると思っていたのと同じように、すぐに動作していないことに気付きました。セカンダリ メニュー、または別のフォームのメニューがあるとすぐに、どのメニューをどのスタイラーの値を使用して描画する必要があるかについて混乱します。これは、理論上、私のメニュー コンポーネントのすべてのインスタンスがグローバル FStyler 変数を使用するためです。

私ができると思ったもう 1 つのことは、オーバーロード ディレクティブでプロシージャをマークすることでした。これにより、追加のパラメーターを追加できるようになりましたが、正しいメニュー コンポーネントを参照しているかどうかはまだわかりません。

私は基本的にコンポーネントの作成などに慣れてきているので、完全に明白な何かを見落としていたら許してください。それが単純な場合、私はそれを完全に見逃しています - 正直に言うと、これは今私をかなり混乱させています!

4

2 に答える 2

5

Menuプロパティ(クラスの祖父母であるで宣言されている)を使用TCustomMenuItemして、次のようなメニュースタイラーにアクセスします。

procedure TMyXPStyleMenuItem.DrawBackground(var PaintRect: TRect);
var
  Styler: TMyStyler;
begin
  if Menu is TMyActionMainMenuBar then
    Styler := TMyActionMainMenuBar(Menu).Styler
  else
    Styler := nil;
  if Assigned(Styler) then
    DrawStyledBackground
  else
    DrawDefaultBackground;
end;

コードをリファクタリングして、GetMenuStylerメソッドを追加できます。

function TMyXPStyleMenuItem.GetMenuStyler: TMyStyler;
begin
  if Menu is TMyActionMainMenuBar then
    Result := TMyActionMainMenuBar(Menu).Styler
  else
    Result := nil;
end;

procedure TMyXPStyleMenuItem.DrawBackground(var PaintRect: TRect);
var
  Styler: TMyStyler;
begin
  Styler := GetMenuStyler;
  if Assigned(Styler) then
    DrawStyledBackground
  else
    DrawDefaultBackground;
end;

procedure TMyXPStyleMenuItem.OtherDrawMethod(var PaintRect: TRect);
var
  Styler: TMyStyler;
begin
  Styler := GetMenuStyler;
  if Assigned(Styler) then
   ...;
end;
于 2013-02-21T22:01:30.227 に答える
3

jachguateの回答を使用すると、GetStylerメソッドの次の行がトリガーされないという問題が発生しました。

function TMyXPStyleMenuItem.GetMenuStyler: TMyStyler;
begin
  if Menu is TMyActionMainMenuBar then //< never hit
    Result := TMyActionMainMenuBar(Menu).Styler
  else
    Result := nil;
end;

カスタム派生メニューが見つからなかったため、これは明らかに残りのコードで問題を引き起こしました。

Menujachguateの回答で指摘されているように、プロパティを使用して少しテストとデバッグを行い、クラス名がそうであるかどうかを確認しましたがTMyActionMainMenuBar、そうではありませんでしTXPStylePopupMenuた。代わりにそうでした。

そのため、クラスをどのように作成できるかを知る必要がありましたTMyActionMainMenuBar

私はいくつかの異なることを試して解決策を見つけました、これが私が見つけたものです:

function TMyXPStyleMenuItem.GetStyler: TMyStyler;
begin
  if Menu.RootMenu is TMyActionMainMenuBar then
    Result := TMyActionMainMenuBar(Menu.RootMenu).Styler
  else
    Result := nil;
end;

その鍵はMenu.RootMenu、カスタムメニューバーが使用されたことを示すでした。

于 2013-02-22T10:39:16.500 に答える