Delphi Programming / Object Pascal
[掲載 2020年08月02日] [更新 2020年08月26日] Delphi 一般・その他
マウスカーソルの移動とフォーム上の位置
動作確認等
Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32
フォーム上のマウスカーソルの位置の取得と移動に関するサンプルです.
このような場合,マウスのローカルフックの利用が考えられます.マウスのローカルフックであれば,非アクティブなフォームやコモンダイアログ等でもマウスカーソルの位置が取得できます.
本ページのサンプルでは,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 上にある時
copy code
// =============================================================================
// 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) としたフォームの座標で表示しています.以下のようにすると,フォームのクライアント領域における座標表示となります.
copy code
// スクリーン座標をフォームのクライアント座標に変換
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 上にある時
copy code
// =============================================================================
// 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) しかありません.以下のようにイベントを共有すれば,マウスカーソル下のコントロールを判定することができます.
copy code
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 ;
イベントは,オブジェクト・インスペクタで設定できますが,以下のように,実行時に設定した方が便利な場合もあります.
copy code
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 を検索した方が便利です.
copy code
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 へ移動
copy code
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 イベントに相当する機能と言えます.手順は上のサンプルコードと同じですが,対象となるコントロールを判定する条件を追加します.
copy code
// =============================================================================
// 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 イベントに相当する機能と言えます.手順は上のサンプルコードと同じですが,対象となるコントロールを判定する条件を変更します.
copy code
// =============================================================================
// 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 の外側にマウスを移動できない
copy code
// =============================================================================
// 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 の座標に変換
copy code
// =============================================================================
// フォーム生成時の処理
// =============================================================================
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
マウスカーソルをフォームまたはコントロール上の任意の位置に移動
copy code
// =============================================================================
// フォーム生成時の処理
// =============================================================================
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
プロパティを使用すると,コントロールのクライアント領域の左上の座標を,スクリーン座標として取得できます.取得したスクリーン座標を使用してマウスカーソルを指定の位置に移動する例です.
copy code
// =============================================================================
// マウスカーソルをフォーム上のコントロールの任意の位置に移動
// 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 プロパティでウィンドウハンドルの値が取得できます.そのウィンドウの矩形領域の座標を基準にした位置にマウスカーソルを移動できます.その例です.
copy code
// =============================================================================
// マウスカーソルをフォーム上のコントロールの任意の位置に移動
// 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 領域内の時と同じ
copy code
// =============================================================================
// 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 のクライアント座標
copy code
// =============================================================================
// 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 ;