Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2020年08月02日] [更新 2020年08月26日] Delphi 一般・その他
マウスカーソルの移動とフォーム上の位置
動作確認等 Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32
[整理番号 - 0620]







マウスカーソルの移動とフォーム上の位置


フォーム上のマウスカーソルの位置の取得と移動に関するサンプルです。
このような場合、マウスのローカルフックの利用が考えられます。マウスのローカルフックであれば、非アクティブなフォームやコモンダイアログ等でもマウスカーソルの位置が取得できます。
本ページのサンプルでは、TApplicationEvents コンポーネントの OnMessage イベントを使用して、アプリケーションが表示するアクティブなフォームだけを対象にしています。また、OnMouseMove イベントを共有する方法もテストしています。
その他にも、マウスカーソルの座標と移動に関するサンプルを掲載しています。

本ページのサンプルの方法を利用すれば、マウスカーソル下のコントロールの判定ができます。
マウスドラック操作によってコントロールがキャプチャ (マウスキャプチャ) されている時は、マウスカーソル下のコントロールの取得方法によって結果が異なる場合ががあります。



[備考]
マウスのドラッグ操作は、ウィンドウとしてのフォームの移動やリサイズ等、オブジェクトの Drag & Drop (ドラッグ・アント・ドロップ) による操作や処理が必要な場合の操作です。文字列の選択や、画像の領域選択操作等でもマウスドラッグが使われます。





01_TApplicationEvents.OnMessage でマウスカーソル位置を取得


TApplicationEvents コンポーネントの OnMessage イベントを使用して、アプリケーションが発行するメッセージ WM_MOUSEMOVE と WM_NCMOUSEMOVE を検出します。WM_NCXXX は、非クライアント領域関係のメッセージです。このメッセージを受信することによって、TMemo 等のスクロールバー部分や、フォームのタイトル部分等のマウスカーソル位置の取得も可能にしています。

WM_MOUSEMOVE メッセージfは。マウスキャプチャの状態 (マウスボタンが押されている状態) でも送信されてきます。コントロールの OnMouseMove イベントも、マウスキャプチャの状態でも発生します。

TApplicationEvents.OnMessage イベントは、名前の通り、アプリケーションレベルのメッセージ捕捉用です。このサンプルでは、別のフォームがアクティブになると、そのアクティブなフォームでのマウスカーソルの移動メッセージを受信します。
アクティブなフォームは、TScreen.ActiveForm, TApplication.ActiveFormHandleプロパティ等を使用して確認できます。



図1
設計時の画面
  • 以下のコンポーネントを配置
    TMemo
    TApplicationEvents ([Additional] タブ)

このサンプルでは、マウスカーソル下のコントロールを、コントロールのウィンドウハンドルの値で判定しています。したがって、TWinControl の派生コントロールでないと判定できません。


図2
マウスカーソルが、フォーム上の Memo1 以外の位置にある時
  • 座標値はフォーム上の値
  • この座標値はフォームの左上が (0, 0)
図3
マウスカーソルが Memo1 上にある時
  • 座標値はフォーム上の値

リスト1
//=============================================================================
//  TApplicationEvents の OnMessage イベント処理
//  フォーム上のマウスカーソル位置の取得
//  マウスカーソル下のコントロールをそのコントロールのハンドル値で判定
//=============================================================================
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LText : string;
begin
  // 非クライアント領域の座標も検出
  if (Msg.message = WM_MOUSEMOVE) or (Msg.message = WM_NCMOUSEMOVE) then begin
    // スクリーン座標をフォームの座標に変換
    LText := IntToStr(Msg.pt.X - Screen.ActiveForm.Left) + ' , '
           + IntToStr(Msg.pt.Y - Screen.ActiveForm.Top);

    // 特定のウィンドウコントロールを検索する例
    if Msg.hwnd = Memo1.Handle then begin
      Memo1.Lines.Text := LText + '  on Memo1';
    end else begin
      Memo1.Lines.Text := LText + '  out of Memo1';
    end;
  end;
end;


上のサンプルでは、マウスカーソルの位置を、左上を (0, 0) としたフォームの座標で表示しています。以下のようにすると、フォームのクライアント領域における座標表示となります。


    // スクリーン座標をフォームのクライアント座標に変換
    LText := IntToStr(Msg.pt.X - Screen.ActiveForm.ClientOrigin.X) + ' , '
           + IntToStr(Msg.pt.Y - Screen.ActiveForm.ClientOrigin.Y);




02_マウスカーソル下のコントロールを FindDragTarget で判定


前項と同じく、ApplicationEvents コンポーネントの OnMessage イベントを使用する例です。
このサンプルでは、マウスカーソル位置のコントロールを判定するのに FindDragTarget 関数を使用しています。
FindDragTarget 関数の戻り値はコントロールのインスタンスでから、コントロールの名前でコントロールを判定できます。したがって、TImage コントロール等の TGraphicControl の派生クラスのコントロールも検出できます。

Enabled プロパティが False のコントロールの場合、FindDragTarget 関数は、そのコントロールの親コントロールのオブジェクトを返します。



図4
マウスカーソルが、フォーム上の、何もコントロールがない位置にある時
  • 座標値はフォーム上の値
  • この座標値はフォームの左上が (0, 0)
図5
マウスカーソルが Image1 上にある時
  • 座標値はフォーム上の値
図6
マウスカーソルが Memo1 上にある時
  • 座標値はフォーム上の値

リスト2
//=============================================================================
//  TApplicationEvents の OnMessage イベント処理
//  フォーム上のマウスカーソル位置の取得
//  マウスカーソル下のコントロールをそのコントロールの名前で判定
//  コントロールの取得に FindDragTarget 関数を使用
//
//  FindDragTarget 関数は Enabled = false のコントロールも検索するが、
//  戻り値はその親コントメールのオブジェクトとなる
//=============================================================================
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LControl : TControl;
  LText    : string;
begin
  // フレーム部分 (タイトル部分等) の位置も検出
  if (Msg.message = WM_MOUSEMOVE) or (Msg.message = WM_NCMOUSEMOVE) then begin
    LControl := FindDragTarget(Msg.pt, True);
    // フォームの領域外にドラッグすると例外が発生するのでその対策
    if LControl = nil then Exit;

    // スクリーン座標をフォームの座標に変換
    LText := IntToStr(Msg.pt.X - Screen.ActiveForm.Left) + ' , '
           + IntToStr(Msg.pt.Y - Screen.ActiveForm.Top);

    // 特定のコントロールを検索する例
    if LControl = Memo1 then begin
    end else begin
    end;
    Memo1.Lines.Text := LText + '  on ' + LControl.Name;
  end;
end;




03_OnMouseMove イベントの共有を利用する方法


イベントは、引数の型と形式と順番、引数の数が同じであれば他のコントロールのイベントと共有できます。上のサンプルでは、フォームには Memo1 (TMemo) しかありません。以下のようにイベントを共有すれば、マウスカーソル下のコントロールを判定することができます。



リスト3
uses
  System.Types;

{$R *.dfm}

//=============================================================================
//  Form1 の OnMouseMove イベント処理
//  Form1 と Memo1 の共有イベント
//
//  uses に System.Types を追加しておく
//=============================================================================
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  LControl : TControl;
  LPoint   : TPoint;
  LText    : string;
begin
  LControl := TControl(Sender);
  if LControl = Self then begin
    LPoint := Point(X, Y);
  end else begin
    // このフォーム (Self) の座標値に変換
    LPoint := LControl.ClientToParent(Point(X, Y), Self);
  end;
  LText := IntToStr(LPoint.X) + ' , ' + IntToStr(LPoint.Y);

  // イベント発生元のコントロールの判定例
  // マウスカーソルはこのコントロール上にある
  if Sender = Memo1 then begin
  end;
  Memo1.Lines.Text := LText + '  on ' + LControl.Name;
end;


イベントは、オブジェクト・インスペクタで設定できますが、以下のように、実行時に設定した方が便利な場合もあります。



リスト4
type
  TMyControl = class(Vcl.Controls.TControl);

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LIndex : Integer;
begin
  for LIndex := 0 to Self.ControlCount - 1 do begin
    TMyControl(Self.Controls[LIndex]).OnMouseMove := Self.OnMouseMove;
  end;
end;


TPanel 等、コンテナコントロール上に配置しているコントロールも対象にする場合は、上のコードを再帰的に実行するよりも、次のように、フォーム上の TComponent を検索した方が便利です。



リスト5
type
  TMyControl = class(Vcl.Controls.TControl);

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LCompo : TComponent;
  LIndex : Integer;
begin
  Memo1.Lines.Clear;

  for LIndex := 0 to Self.ComponentCount - 1 do begin
    LCompo := Self.Components[LIndex];
    if LCompo is TControl then begin
      TMyControl(LCompo).OnMouseMove := Self.OnMouseMove;
    end;
  end;
end;




04_マウスカーソルの別コントロールへの移動を検出


マウスカーソルがどのコントロール上にあるかが分かれは、マウスカーソルが別のコントロール上に移動したことが検出できます。その例です。
現在のマウスカーソル下のコントロールと、前にマウスカーソルがあったコントロールが異なる場合だけ処理します。そのために、TControl 型のグローバル変数を用意して、それに以前のマウスカーソル下のコントロールを代入して保持するようにします。



図7
実行例
  • 以下の順番でマウスカーソルを移動
  • フォームの外側から Button1 へ移動
    当然 Form1 を通過する
  • Button1 から Form1 へ移動
  • Form1 から Memo1 へ移動

リスト6
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.AppEvnts;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    ApplicationEvents1: TApplicationEvents;
    Button1: TButton;
    procedure ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;
  FPreControl : TControl = nil;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.ScrollBars := ssVertical;
end;

//=============================================================================
//  TApplicationEvents の OnMessage イベント処理
//  フォーム上のマウスカーソル位置の取得
//  マウスカーソル下のコントロールが変わったらそのコントロール名を表示
//
//  FPreControl (TControl) はグローバル変数
//=============================================================================
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LControl : TControl;
  LSrcName : string;
  LDstName : string;
begin
  // フレーム部分 (タイトル部分等) の位置も検出
  if (Msg.message = WM_MOUSEMOVE) or (Msg.message = WM_NCMOUSEMOVE) then begin
    LControl := FindDragTarget(Msg.pt, True);

    // マウスカーソル下のコントロールが前と異なる場合 
    if LControl <> FPreControl then begin
      if FPreControl = nil then begin
        LSrcName := 'out of form';
      end else begin
        LSrcName := FPreControl.Name;
      end;

      if LControl = nil then begin
        LDstName := 'out of form';
      end else begin
        LDstName := LControl.Name;
      end;
      Memo1.Lines.Add(IntToStr(Memo1.Lines.Count) + ' : '
                      + LSrcName + ' -->  ' + LDstName);
    end;

    // 現在のマウスカーソル下のコントロールを記憶しておく
    FPreControl := LControl;
  end;
end;

end.




05_マウスカーソルの特定コントロール領域内への移動を検出


特定のコントロール上にマウスカーソルが移動してきたことを検出する例です。OnMouseEnter イベントに相当する機能と言えます。手順は上のサンプルコードと同じですが、対象となるコントロールを判定する条件を追加します。



リスト7
//=============================================================================
//  TApplicationEvents の OnMessage イベント処理
//  Memo1 以外から Memo1 上にマウスカーソルが移動した場合のみ処理
//
//  FPreControl (TControl) はグローバル変数
//=============================================================================
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LControl : TControl;
begin
  // フレーム部分 (タイトル部分等) の位置も検出
  if (Msg.message = WM_MOUSEMOVE) or (Msg.message = WM_NCMOUSEMOVE) then begin
    LControl := FindDragTarget(Msg.pt, True);

    // マウスカーソル下のコントロールが前と異なる場合で、
    // マウスカーソルの移動先が Memo1 の場合
    if (LControl <> FPreControl) and (LControl = Memo1) then begin
      Memo1.Lines.Add(IntToStr(Memo1.Lines.Count) + ' : '
                      + FPreControl.Name + ' -->  ' + LControl.Name);
    end;

    // 現在のマウスカーソル下のコントロールを記憶しておく
    FPreControl := LControl;
  end;
end;




06_マウスカーソルの特定コントロール領域外への移動を検出


特定のコントロールの領域外へ移動したことを検出する例です。コントロールの OnMouseLeave イベントに相当する機能と言えます。手順は上のサンプルコードと同じですが、対象となるコントロールを判定する条件を変更します。



リスト8
//=============================================================================
//  TApplicationEvents の OnMessage イベント処理
//  Memo1 から Memo1 以外の場所にマウスカーソルが移動した場合のみ処理
//
//  FPreControl (TControl) はグローバル変数
//=============================================================================
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LControl : TControl;
begin
  // フレーム部分 (タイトル部分等) の位置も検出
  if (Msg.message = WM_MOUSEMOVE) or (Msg.message = WM_NCMOUSEMOVE) then begin
    LControl := FindDragTarget(Msg.pt, True);

    // マウスカーソル下のコントロールが前と異なる場合で、
    // 前にマウスカーソルがあったのが Memo1 の場合
    if (LControl <> FPreControl) and (FPreControl = Memo1) then begin
      Memo1.Lines.Add(IntToStr(Memo1.Lines.Count) + ' : '
                      + FPreControl.Name + ' -->  ' + LControl.Name);
    end;

    // 現在のマウスカーソル下のコントロールを記憶しておく
    FPreControl := LControl;
  end;
end;




07_マウスカーソルのコントロール領域外への移動を禁止


Windows API の ClipCursor 関数を使用すると、マウスの移動をクリップして、指定した矩形領域の外側にはマウスカーソルを移動できなくすることができます。
このサンプルでは、マウスの左ボタンを押した状態でマウスを移動した時は、Panel1 の領域外にはマウスカーソルを移動できないようにしています。マウスの左ボタンを押した時にクリップを開始して、ボタンを離すとクリップを解除します。



図8
マウスの左ボタンを押した状態の時は、Panel1 の外側にマウスを移動できない

リスト9
//=============================================================================
//  TApplicationEvents の OnMessage イベント処理
//  マウスカーソル下のコントロールをそのコントロールのハンドル値で判定
//
//  特定のコントロールの領域外へのマウスカーソルの移動の禁止と解除
//=============================================================================
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LRect : TRect;
begin
  if (Msg.hwnd = Panel1.Handle) then begin
    if (Msg.message = WM_LBUTTONDOWN) then begin
      // マウスの移動をクリップ
      GetWindowRect(Panel1.Handle, LRect);
      ClipCursor(@LRect);
    end;
    if (Msg.message = WM_LBUTTONUP) then begin
      // マウスの移動クリップを解除
      ClipCursor(nil);
    end;
  end;
end;




08_コントロール上の座標値とフォーム上の座標値の変換


コントロールのクライアント座標値をフォームのクライアント座標値に変換するには、TControl に実装されている ClientToParent メソッドが利用できます。その例です。
この関数は、対象のコントロールの親コントロールにおける座標値を取得するメソッドですが、親の親、そのまた親も指定できます。
逆の変換には、TControl の ParentToClient メソッドが利用できます。



図9
Panel2 の座標を Form1 の座標に変換

リスト10
//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Panel1.ParentBackground := False;
  Panel2.ParentBackground := False;

  Panel1.Color := clSkyBlue;
  Panel2.Color := clGreen;

  Panel1.Left := 50;
  Panel1.Top  := 60;
//
  Panel2.Left := 30;
  Panel2.Top  := 10;
end;

//=============================================================================
//  Panel2 の OnMouseMove イベント処理
//  コントロール内の座標値をフォームの座標値に変換
//  共にクライアント領域の座標
//=============================================================================
procedure TForm1.Panel2MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  LFormPos : TPoint;
  LText    : string;
begin
  LFormPos := Panel2.ClientToParent(Point(X, Y), Form1);

  LText := IntToStr(X) + ' , ' + IntToStr(Y) + '  at ' + TControl(Sender).Name
         + sLineBreak + IntToStr(LFormPos.X) + ' , ' + IntToStr(LFormPos.Y) + '  at Form1';
  Memo1.Lines.Text := LText;
end;




09_マウスカーソルをコントロール上の任意の位置に移動


TMouse の CursorPos プロパティを使用すると、マウスカーソルを、フォームあるいはフォーム上のコントロールの任意の位置に移動できます。
このプロパティは、マウスカーソルの位置の設定と取得に使用できまずか、扱う座標値はスクリーン座標です。TControl.ClientToScreen メソッドでスクリーン座標に変換してから代入します。



図10
マウスカーソルをフォームまたはコントロール上の任意の位置に移動

リスト11
//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Panel1.ParentBackground := False;
  Panel2.ParentBackground := False;

  Panel1.Color := clSkyBlue;
  Panel2.Color := clGreen;

  Panel1.Left := 50;
  Panel1.Top  := 60;
//
  Panel2.Left := 30;
  Panel2.Top  := 10;
end;

//=============================================================================
//  マウスカーソルをフォーム上のコントロールの任意の位置に移動
//  TMouse.CursorPos を使用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LCtrlPos : TPoint;
  LFormPos : TPoint;
  LText    : string;
begin
  // Panel2 上の座標値を指定して、フォーム上の座標値に変換
  LCtrlPos := Point(5, 10);
  LFormPos := Panel2.ClientToParent(LCtrlPos, Form1);

  LText := IntToStr(LCtrlPos.X) + ' , ' + IntToStr(LCtrlPos.Y) + '  at Panel2'
         + sLineBreak + IntToStr(LFormPos.X) + ' , ' + IntToStr(LFormPos.Y) + '  at Form1';
  Memo1.Lines.Text := LText;


  // 実際にマウスカーソルを移動
  Mouse.CursorPos := Panel2.ClientToScreen(LCtrlPos);
  // 以下でも同じ
  // この場合の Self は Form1。Self は省略できる
  // Mouse.CursorPos := Form1.ClientToScreen(LFormPos);
  // Mouse.CursorPos := Self.ClientToScreen(LFormPos);
  // Mouse.CursorPos := ClientToScreen(LFormPos);
end;


TControl.ClientOrigin プロパティを使用すると、コントロールのクライアント領域の左上の座標を、スクリーン座標として取得できます。取得したスクリーン座標を使用してマウスカーソルを指定の位置に移動する例です。


//=============================================================================
//  マウスカーソルをフォーム上のコントロールの任意の位置に移動
//  TMouse.CursorPos を使用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LCtrlPos : TPoint;
begin
  // コントロールのクライアント領域の左上のスクリーン座標を取得
  LCtrlPos := Panel2.ClientOrigin;
  // 位置の値を指定してマウスカーソルをそこに移動
  LCtrlPos.Offset(5, 10);
  Mouse.CursorPos := LCtrlPos;
end;


TPanel は TWinControl の派生クラスのコントロールです。Handle プロパティでウィンドウハンドルの値が取得できます。そのウィンドウの矩形領域の座標を基準にした位置にマウスカーソルを移動できます。その例です。


//=============================================================================
//  マウスカーソルをフォーム上のコントロールの任意の位置に移動
//  TWindControl の派生コントロールの例
//  TMouse.CursorPos を使用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LWndRect : TRect;
begin
  // コントロールの矩形領域を取得
  GetWindowRect(Panel2.Handle, LWndRect);
  // 位置の値を指定してマウスカーソルをそこに移動
  Mouse.CursorPos := TPoint.Create(LWndRect.Left + 5, LWndRect.Top + 10);
end;




10_OnMouseMove イベントはそのコントロール専用


多くの TControl の派生クラスには OnMouseMove イベントが実装されています。 OnMouseMove イベントに限らず、他のコントロールとイベントを共有しなければ、それらのコントロール (クラス) のメンバとしてのイベントは、そのコントロール専用です。OnMouseMove イベントの場合、そのコントロールの領域内でないと OnMouseMove イベントは発生しません。
コントロール (クラス) のメンバとしての WM_MOUSEMOVE メッセージも同じです。

下に示すコードは TMemo の OnMouseMove イベント処理の例です。このイベントのコードは、マウスカーソルが Memo1 の領域内にないと実行されません。したがって、マウスカーソルが Memo1 の領域外へ移動したか、Memo1 の領域内へ移動したかを検出することはできません。



図11
マウスカーソルを Memo1 から Memo1 以外の位置 に移動した時
  • かなりの勢いで Memo1 の外にマウスカーソルを移動した結果
  • OnMouseMove イベントは発生していない
  • 表示されている座標値は、マウスカーソルが Memo1 領域内にあった時の値
図12
マウスカーソルを Memo1 以外の別の位置に移動した場合
  • OnMouseMove イベントは発生していない
  • 表示されている座標値が上の図と同じ
  • この座標値は、マウスカーソルが Memo1 領域内にあった時の値

マウスの左ボタンを押した状態でマウスカーソルを移動すると、マウスのドラッグ操作となります。マウスのドラッグ操作の場合は、コントロールのキャプチャ (マウスキャプチャ) が行われます。コントロールがキャプチャされると、マウスはそのコントロール上にあるのと同じとなります。その結果、ドラッグ中はこのイベントが発生します。
TMemo におけるマウスの左ボタン押下状態のマウスドラッグの操作は、文字列 (テキスト) の選択操作となります。



図13
マウスドラッグの場合
  • Memo1 から Form1 へドラッグ操作でマウスを移動
  • 座標値は Memo1 における値
  • マウスカーソルも Memo1 領域内の時と同じ

リスト12
//=============================================================================
//  Memo1 の OnMouseMove イベント処理
//=============================================================================
procedure TForm1.Memo1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  LCurPos  : TPoint;
  LLeftTop : TPoint;
  LInRect  : TRect;
  LText    : string;
begin
  // TMemo の領域外も検出のため現在のスクリーンカーソル位置を取得
  GetCursorPos(LCurPos);

  LLeftTop := Self.ClientToScreen(Point(Memo1.Left, Memo1.Top));
  LInRect  := TRect.Create(LLeftTop, Memo1.Width, Memo1.Height);

  LText := IntToStr(X) + ' , ' + IntToStr(Y);
  if PtInRect(LInRect, LCurPos) then begin
    Memo1.Lines.Text := LText + '  on Memo1';
  end else begin
    // ここはドラッグ操作でないと実行されない
    Memo1.Lines.Text := LText + '  out of Memo1';
  end;
end;

コントロールがマウスキャプチャされている状態の時、つまり、マウスドラッグの場合に、マウスカーソル下のコントロールを FindDragTarget 関数を使用して取得する例です。この場合は、ドロップ先であるかも知れない、マウスカーソルがある位置のコントロールが取得できます。上のコードのような矩形領域による判定は必要ありません。



図14
マウスドラッグ時のマウスカーソル下のコントロールを FindDragTarget 関数で判定
  • Memo1 から Form1 へマウスドラッグ
  • 表示座標は Form1 のクライアント座標

リスト13
//=============================================================================
//  Memo1 の OnMouseMove イベント処理
//=============================================================================
procedure TForm1.Memo1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  LControl : TControl;
  LCurPos  : TPoint;
  LPos     : TPoint;
  LText    : string;
begin
  // イベントの引数はクライアント座標なのでスクリーン座標に変換
  LCurPos := Mouse.CursorPos;

  // マウスカーソル位置のコントロールを取得
  LControl := FindDragTarget(LCurPos, True);

  if LControl <> nil then begin
    // マウスカーソルのクライアント座標を取得して表示
    LPos  := LControl.ScreenToClient(LCurPos);
    LText := IntToStr(LPos.X) + ' , ' + IntToStr(LPos.Y) + '  on ' + LControl.Name;
        Memo1.Lines.Text := LText;
  end else begin
    Memo1.Lines.Text := '';
  end;
end;