マウスカーソルがあるモニターの画面中央にFormを表示する [C++Builer]

マルチモニター環境でマウスカーソルがあるモニターに Form ウィンドウを表示する方法です。

アプリを起動したり再表示したりしたとき、多くのアプリは前回と同じ位置に表示されます。マルチモニター環境で窓替えやランチャーのようなアプリを使う場合には、前回と同じ位置ではなく、いま見ているモニターに表示された方が便利です。

C++Builder では Form の DefaultMonitor プロパティや Position プロパティの値を組み合わせて表示位置を指定することが出来ますが、マウスカーソルのあるモニターの指定はありません。

このページでは、マルチモニター環境でマウスカーソルがあるモニターの中央に Form ウィンドウを表示する方法を記載します。

Unit1.cpp

void __fastcall TForm1::FormShow(TObject *Sender)
{
    // アプリ起動時は、ウィンドウが表示される前に移動する
	MoveWindowToMonitorWhereMouseCursorIsLocated();
}

void __fastcall TForm1::FormResize(TObject *Sender)
{
    // 最小化状態から元に戻した時もウィンドウを移動する
    MoveWindowToMonitorWhereMouseCursorIsLocated();
}

//---------------------------------------------------------------------------
// 概要
//   マウスカーソルがあるモニターにウィンドウを移動する
//---------------------------------------------------------------------------
void TForm1::MoveWindowToMonitorWhereMouseCursorIsLocated()
{
	// マウスカーソルがあるモニターの作業領域座標・ RECT 構造体を取得する
	RECT rt = GetMonitorWorkRectFromCursor();

	// 自ウィンドウをモニターの中心に移動する
	Left = (rt.left + ((rt.right - rt.left) / 2)) - (Form1->Width / 2);
	Top = (rt.top + ((rt.bottom - rt.top) / 2)) - (Form1->Height / 2);
}

//---------------------------------------------------------------------------
// 概要
//   マウスカーソルがあるモニターの作業領域座標・ RECT 構造体を取得する
// パラメーター
//   なし
// 戻り値
//   RECT 構造体が返る。
//   成功:マウスカーソルがあるモニターの作業領域座標が入る。
//   失敗:含まれる値全てが 0 になる。
//---------------------------------------------------------------------------
RECT TForm1::GetMonitorWorkRectFromCursor()
{
	RECT emptyRect {0,0,0,0};

	// マウスカーソルの画面座標を取得する
	POINT point;
	if (GetCursorPos(&point) == 0)
		return emptyRect;

	// マウスカーソルの画面座標の在るモニターへのハンドルを取得する
	HMONITOR hMonitor = MonitorFromPoint(point, MONITOR_DEFAULTTOPRIMARY);

	// モニターハンドルからモニター情報を取得する。
	MONITORINFO monitorInfo;
	monitorInfo.cbSize = sizeof(monitorInfo);
	if (GetMonitorInfo(hMonitor, &monitorInfo) == 0)
		return emptyRect;

    // モニター情報に含まれている作業領域の座標を表す RECT 構造体を返す。
	return monitorInfo.rcWork;
}

ウィンドウの移動は FormShow() と FormResize() で行います。

FormShow() で行うのは、アプリ起動時にウィンドウが表示される前に移動しておくためです。
FormShow()以降のイベントである FormPaint()、FormActivate()、FormResize() で行うと、デフォルト位置に一度表示されてしまいますので、表示される前に移動するようにしています。

FormResize() で行うのは、元に戻す時にもウィンドウを移動できるようにするためです。
元に戻した時には FormActivate() や FormShow() は発生しないので、元に戻すでも発生する FormResize() で行います。FormResize() はアプリ起動時にも発生するため、前述の FormShow() と二回実行されますが動作上の問題はありません。もし一回だけ実行したいのであれば、FormResize() 側を実行しないように抑止するのが良いです。

参考

コメント