Delphi は、Borland が提供するまったく新しい WINDOWS プログラミング開発ツールです。柔軟で再利用可能なオブジェクト指向 Pascal (オブジェクト指向パスカル) 言語を使用し、強力なデータベース エンジン (BDE) を備えているため、高速なコード コンパイラも数多く提供されています。多くのプログラミング言語 (VB、PowerBuilder、Powerpoint など) の中で、大多数のプログラマーに好まれています。
他のプログラミング言語 (VB4.0 など) に対する DELPHI の利点の 1 つは、DELPHI でメッセージをカスタマイズでき、直接処理できることです。 これは、独自のコンポーネント (コンポーネント) を作成したい人向けです。コンポーネントを作成するには、通常、対応するメッセージを処理する必要があるため、これは、Delphi のメッセージ処理メカニズムの概要です。
1. DELPHI VCL でのメッセージ配信
Delphi の各 VCL (Visual Component Library) コンポーネント (Tbutton、Tedit など) には、固有のメッセージ処理メカニズムがあり、その基本的な点は、コンポーネント クラスが特定のメッセージを受信し、存在する場合はそれらを適切な処理メソッドに送信することです。特定の処理メソッドがない場合は、デフォルトのメッセージ処理ハンドルが呼び出されます。このうち、mainwndPRoc は Twincontrol クラスで定義された静的メソッドであり、オーバーロード(Override)することはできません。メッセージは直接処理されませんが、wndproc メソッドに処理を任せ、wndproc メソッドに例外処理モジュールを提供します。 Mainwndproc メソッドは次のように宣言されます。
プロシージャ MainWndProc(var メッセージ: TMessage);
Wndproc は Tcontrol クラスで定義された仮想メソッドであり、メッセージを配布するためにディスパッチ メソッドを呼び出します。 wndproc メソッドは次のように宣言されます。
プロシージャ WndProc(var メッセージ: TMessage);
ディスパッチ メソッドは Tobject ルート クラスで定義され、次のように宣言されます。
プロシージャ Tobject.dispatch(var Message); ディスパッチに渡されるメッセージ パラメータはレコード タイプである必要があり、このレコードの最初のエントリ ポイントは、配布されるメッセージのメッセージを含むカーディナル タイプ フィールド (フィールド) である必要があります。 。 例えば:
タイプ
Tメッセージ=レコード
メッセージ:枢機卿;
wparam:ワード;
lparam:倍長整数。
結果:倍長整数;
終わり;
Dispatch メソッドは、メッセージ番号に基づいてこのメッセージを処理するコンポーネントの最後の世代クラスのハンドル メソッドを呼び出します。このコンポーネントとその祖先クラスにこのメッセージに対応するハンドラーがない場合、Dispatch メソッドは Defaulthandler を呼び出します。 Defaulthandler メソッドは、Tobject で定義された仮想メソッドは次のように宣言されます。
プロシージャ Defaulthandler(var Message);virtual;
Tobject クラスの Defaulthandler メソッドは、メッセージの処理を行わずに単純な戻り値のみを実装します。VCL のコンポーネントの場合、その Defaulthandler メソッドがウィンドウを起動することで、サブクラスにメッセージのデフォルトの処理を実装できます。メッセージを処理するための API 関数 Defwindowproc。
2. DELPHI のメッセージ処理ハンドル
DELPHI では、ユーザーはメッセージとメッセージ処理ハンドルをカスタマイズできます。メッセージ処理ハンドルの定義には次の原則があります。
メッセージ処理ハンドル メソッドはプロシージャである必要があり、Tmessage タイプの変数パラメータを 1 つだけ渡すことができます。
メソッド宣言の後にはメッセージ コマンドが続き、その後に 0 ~ 32767 のメッセージ ラベル (整数定数) が続く必要があります。
メッセージ ハンドラー メソッドは、祖先のメッセージ ハンドラーのオーバーライドを明示的に示すために override コマンドを使用する必要はありません。また、通常はコンポーネントの保護領域またはプライベート領域で宣言されます。
メッセージ処理ハンドルでは、ユーザーは通常、最初にメッセージを処理し、最後に継承されたコマンドを使用して、祖先クラス内のこのメッセージに対応する処理ハンドルを呼び出します (場合によっては、その処理ハンドルが逆になる場合もあります)。祖先クラスのこのメッセージは名前とパラメータの型が不明瞭である可能性があり、継承されたコマンドを呼び出すことでこの問題を回避できます。同様に、祖先クラスにこのメッセージに対応するハンドラがない場合、継承されたコマンドは自動的に Defaulthandler メソッドを呼び出します。 (もちろん、このメッセージをブロックしたい場合は、継承したコマンドを使用する必要はありません)。
メッセージ ハンドラー メソッドは次のように宣言されます。
プロシージャ Mymsgmethod(var message:Tmessage);
同様に、ユーザーは独自のメッセージを定義することもできます。ユーザー定義のメッセージは WM_USER で始まる必要があります。
カスタム メッセージとメッセージ処理ハンドルの例は次のとおりです。
const my_paint=Wm_user+1;
タイプ
Tmypaint=レコード
msgstr:基数;
msize:ワード;
mcolor:倍長整数;
msgresult:倍長整数;
終わり;
タイプ
Tmycontrol=クラス(TCustomControl)
保護された
プロシージャ変更(var message:Tmypaint);
……
終わり;
...
プロシージャ Tmycontrol.change(var message:Tmypaint);
始める
size:=message.msize; {Tmybutton サイズ属性を設定}
color:=message.mcolor; {Tmybutton の色属性を設定}
{何か他のことをする}
継承; { Tcustomcontrol に渡される}
終わり;
3. メッセージのフィルタリング
メッセージのフィルタリングはメッセージ トラップとも呼ばれます。 特定の状況下では、ユーザーは特定のメッセージをブロックしたり、処理のために特定のメッセージを傍受したりする必要がある場合があります。 上記の説明から、メッセージをフィルターするには次の 3 つの方法があることがわかります: (1) コンポーネントによって継承された仮想メソッド wndproc をオーバーロードする (2) 特定のメッセージのメッセージ処理ハンドルを作成します。コンポーネントによって継承された仮想メソッド Defhandler をオーバーロードし、メッセージが処理されます。 最も一般的に使用される方法は、前のセクションで紹介した方法 (2) です。方法 (1) は、方法 (3) と同様です。ここでは、方法 (1) について簡単に説明します。
仮想メソッド wndproc をオーバーロードする一般的なプロセスは次のとおりです。
プロシージャ Tmyobject.wndproc(var message:Tmessage);
始める
{... このメッセージを処理する必要があるかどうかを決定します。}
継承された wndproc(メッセージ);
{未処理のメッセージは親の wndproc メソッドによって処理されます}
終わり;
このことから、wndproc メソッドでメッセージを処理する利点は、各メッセージの処理ハンドルを指定せずにメッセージの全範囲をフィルタリングできることであることがわかります。実際、このメソッドはフィルタリングとフィルタリングを行うために Tcontrol コンポーネントで使用されます。すべてのマウス メッセージを処理します (次のコードに示すように、WM_mousefirst から WM_mouselast まで)。これは、特定のメッセージがハンドラーに送信されないようにするためにも使用できます。
プロシージャ TControl.WndProc(var メッセージ: TMessage);
始める
if (Message.Msg>=WM_MOUSEFIRST) および
(Message.Msg <= WM_MOUSELAST)
それから
ドラッグの場合は {ハンドル ドラッグ イベント}
DragMouseMsg(TWMMouse(メッセージ))
それ以外
... {他のマウス メッセージを処理する}
終わり;
ディスパッチ(メッセージ);
{それ以外の場合は通常どおりメッセージを送信します}
終わり;
次の例は、単純なカスタム コンポーネントの例です。
Tmyedit クラスは、Tedit クラスから派生した新しいクラスです。その特徴は、操作中にフォーカスを取得できず、キーボードで入力できないことです (Tlabel コンポーネントと似ています)。WM_setfocus および WM_mousemove メッセージをフィルタリングできます。 wndproc メソッドを実行して上記の要件を実現するためのソース プログラムは次のとおりです。
ユニットmyedit;
インタフェース
用途
ウィンドウ、メッセージ、SysUtils、クラス、グラフィックス、
コントロール、フォーム、ダイアログ、
StdCtrls;
タイプ
Tmyedit = クラス(TEdit)
プライベート
{プライベート宣言}
保護された
{ 保護された宣言 }
{その他のフィールドとメソッド}
プロシージャ wndproc(var message:Tmessage);オーバーライド;
公共
{公的宣言}
出版された
{ 公開された宣言 }
終わり;
手順 登録;
実装
手順 登録;
始める
RegisterComponents('サンプル', [Tmyedit]);
終わり;
プロシージャ Tmyedit.wndproc(var message:tmessage);
始める
message.msg=wm_mousemove の場合
始める
カーソル:=クロー;
{デフォルトの crBeam カーソルの代わりにカーソルを crarrow に設定します}
出口;
終わり;
message.msg=wm_SetFocus の場合は終了します。
{WM_setfocus メッセージをシールドし、Tmyedit コントロールが入力フォーカスを取得できないようにします}
継承された wndproc(メッセージ);
{他のメッセージは処理のために親の wndproc に渡されます}
終わり;
終わり。
Tmyedit をコンポーネント パレットに追加して、そのパフォーマンスをテストできます。
上記の紹介からわかるように、Delphi VCL のメッセージ処理メカニズムを理解し、さまざまなメッセージを処理する方法とタイミングを習得し(必要に応じて winsight32 や spy などのさまざまなツールを使用します)、その特性を組み合わせるだけで済みます。 OOP 言語のおかげで、高品質のコンポーネントをコンパイルできます。 もちろん、これには読者が常に探求し、実際の経験を蓄積することが必要です。