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;