6

Delphi 7で、イベントの伝播に関する問題に悩まされています(私の無知のため)。

OnMouseUpフォームの一部のコントロールにイベントハンドラーを動的にアタッチするように求められますが(それで問題ありません)、がOnMouseUp存在する場合はOnClick、そのコントロールのイベントを処理しないでください。

バックグラウンド

この背後にある理由を尋ねているのであれば、私は古い生産監視アプリケーション(ため息)を変更する責任があります。これは、特別な機能の以前のクリックに直接応答して、一部のコントロールの条件付き動作に対応する必要がありますボタン。

これらのコントロールの一部には、OnClickすでにイベントハンドラーがあります。チームが思いついた最初の解決策は、各OnClickハンドラーに時間通りに介入し、特殊機能ボタンのステータスに関連するコンテキストアクションを管理することでした。

アプリケーションフォームにすでに配置されているオブジェクト指向設計を利用することを提案しました。これらはすべて同じカスタムの祖先オブジェクトから継承するため、OnMouseUpサポートするように宣言されたコントロールにイベントを動的にアタッチするために、そこに初期化メソッドを挿入することを計画しました。サブクラスでそれ。

必要なもの

私はここで、これらすべてについての(おそらく欠如している)設計の良さについて検証や質問をしているのではありません(ちなみに、多くの考えと推論の結果、それは私たちがより少ない痛みで歩くことができる道のようでした)。私の問題は、そのような設計を行うには、動的に接続されたイベントハンドラーに、これらのコントロール上OnMouseUpの既存のイベントへのイベントの伝播を停止させる必要があることです。OnClick

Delphi 7で可能ですか?

4

2 に答える 2

6

以下は、ここでの質問に明示的に回答していないことに注意してください。これは、コンセプトの再設計への提案です (OnMouseUp を追加する代わりに、OnClick イベントをリダイレクトします)。すべてのコンポーネント (必要に応じてフィルタリングされる可能性があります) の OnClick イベント ハンドラー (割り当てられている場合) を別の (共通の) OnClick イベント ハンドラーにリダイレクトする方法についてです。それらを元の状態に戻す方法も含まれています。

次の例では、OnClick イベント ハンドラー (コンポーネントが何かを記述している場合) を特定のイベント ハンドラーに置き換え、必要に応じて復元する方法を示します。これは、OnClick イベントが公開されているすべてのコンポーネントに対して行われるため、コンポーネント クラスで OnClick イベントが利用可能かどうかを事前に知る必要はありません (ただし、特定のクラスのみを使用するように非常に簡単に変更できます)。

コードは次のものから構成されます。

  • OnSpecialClick - これは、ReplaceOnClickEvents プロシージャを呼び出したときにすべての OnClick イベントがバインドされるイベント ハンドラです。RTTI で表示するには公開する必要があることに注意してください !!!

  • Button1Click - ここでは、置き換える必要がある古いイベント ハンドラーを表します。これは、設計時に Button1.OnClick イベントにバインドされます。

  • ReplaceOnClickEvents - フォーム上のすべてのコンポーネントを反復処理し
    、現在反復処理されているコンポーネントに OnClick イベント ハンドラが割り当てられているかどうかをチェックするメソッド。その場合、それをバックアップ コレクションに格納し、このイベント ハンドラーを OnSpecialClick に置き換えます。

  • RestoreOnClickEvents - 元の OnClick イベント ハンドラを復元するメソッド。バックアップ コレクションを反復処理し、格納されているコンポーネント インスタンスにイベント メソッドを割り当てます。

  • CheckBox1Click - このチェック ボックス クリック イベントは、一般的なモードと特別なモードの間の切り替えを意味します (CheckBox1 のチェック状態は特別なモードであることを意味します)。この OnClick イベントのみが、ReplaceOnClickEvents 呼び出しによって置き換えられません (モードを通常に戻すことができます)

そして、ここにあります:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TypInfo, StdCtrls, Contnrs;

type
  TEventBackup = class
    Component: TComponent;
    OnClickMethod: TMethod;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
  private
    procedure ReplaceOnClickEvents;
    procedure RestoreOnClickEvents;
  published
    procedure OnSpecialClick(Sender: TObject);
  end;

var
  Form1: TForm1;
  EventBackupList: TObjectList;

implementation

{$R *.dfm}

procedure TForm1.OnSpecialClick(Sender: TObject);
begin
  ShowMessage('Hi, I''m an OnSpecialClick event message!');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('Hi, I''m just that boring original OnClick event message!');
end;

procedure TForm1.ReplaceOnClickEvents;
var
  I: Integer;
  Component: TComponent;
  EventMethod: TMethod;
  EventBackup: TEventBackup;
begin
  for I := 0 to ComponentCount - 1 do
  begin
    Component := Components[I];
    if Component = CheckBox1 then
      Continue;

    if IsPublishedProp(Component, 'OnClick') then
    begin
      EventMethod := GetMethodProp(Component, 'OnClick');
      if Assigned(EventMethod.Code) and Assigned(EventMethod.Data) then
      begin
        EventBackup := TEventBackup.Create;
        EventBackup.Component := Component;
        EventBackup.OnClickMethod := EventMethod;
        EventBackupList.Add(EventBackup);
        EventMethod.Code := MethodAddress('OnSpecialClick');
        EventMethod.Data := Pointer(Self);
        SetMethodProp(Component, 'OnClick', EventMethod);
      end;
    end;
  end;
end;

procedure TForm1.RestoreOnClickEvents;
var
  I: Integer;
  EventBackup: TEventBackup;
begin
  for I := 0 to EventBackupList.Count - 1 do
  begin
    EventBackup := TEventBackup(EventBackupList[I]);
    SetMethodProp(EventBackup.Component, 'OnClick', EventBackup.OnClickMethod);
  end;
  EventBackupList.Clear;
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if CheckBox1.Checked then
    ReplaceOnClickEvents
  else
    RestoreOnClickEvents;
end;

initialization
  EventBackupList := TObjectList.Create;
  EventBackupList.OwnsObjects := True;

finalization
  EventBackupList.Free;

end.
于 2012-05-08T11:06:30.283 に答える
1

TLama と TOndrej の両方が言っているように、試みていることを達成するにはいくつかの方法があります。

  1. イベントハンドラーif Assigned(Control.OnMouseUp) then Exit;で行うことOnClick

  2. OnClick割り当て時にイベントを「割り当て解除」するにはOnMouseUp(およびその逆)

どちらのアプローチでも、詳細を説明したことを達成できますが、ステートメントを繰り返し実行することはないため、イベントの「割り当てを解除」OnClickするのがパフォーマンスに最適です (無限大に小さい程度まで) 。if

于 2012-05-08T10:48:54.160 に答える