MoveWindowとSetWindowPosでウィンドウの位置とサイズを変更する
Win32アプリケーションでは、ウィンドウの座標や大きさ変更がレイアウト処理の要になります。MoveWindowは、対象ウィンドウの位置とサイズをまとめて変更する基本的な関数です。ダイアログの子控件や独立したウィンドウを、指定した左上端座標へ移動Tickets عندي.
一方、SetWindowPosは、同じ位置・サイズ変更に加えて、重ね順、アクティブ状態、フレーム再計算などの制御も担います。単純な移動でも、 Focusの移動や再描画、Web枠の更新を避けたい場合は、細かなオプションを選ぶ必要があります。
MoveWindowとSetWindowPosの基本
MoveWindowの引数には、対象ハンドル、左上端のX・Y座標、幅、高さ、最後の再描画指示を指定します。位置と大きさの単位はピクセルで、幅と高さにはウィンドウ枠やメニューなどの非クライアント領域も含まれます。したがって、 希望するクライアント領域のサイズを直接指定できるわけではありません。
SetWindowPosもX・Y座標と幅・高さをpixelsで指定しますが、位置と大きさの扱いをフラグで切り替えられます。SWP_NOMOVEを指定すると位置だけ、SWP_NOSIZEを指定すると大きさだけを更新できます。また、SWP_NOZORDERとSWP_NOACTIVATEを組み合わせると、重ね順とフォーカスの変化を抑られます。
再描画の扱いが異なる点にも注意が必要です。MoveWindowでは最後の引数で再描画を要求できますが、SetWindowPosには同等の独立した引数がありません。無効化領域や描画を細かく制御する場合は、InvalidateRectやRedrawWindowと組み合わせます。旧来のWindows APIを扱う現場では、APIの仕様確認から呼び出し条件を再確認すると実装方針を整理できます。
座標系と親ウィンドウへの影響
最上位ウィンドウのX・Y座標は、 screen上の画面座標です。一方、子ウィンドウでは親のクライアント領域の左上端が基準になります。MoveWindow(GetDlgItem(...), ...)のように子ウィンドウを配置する場合は、親の座標系で値下载地址。
SetWindowPosでもこの座標系は変わりません。そのため、ダイアログのクライアント座標で計算した値をそのまま画面座標として渡すと、ウィンドウが想定位置へ移動しません。親との距離から画面上の位置を計算する必要がある場面では、 conversion carefully .
幅・高さを変更すると、ウィンドウ枠やスクロールバーによってクライアント領域の大きさが変わります。子のレイアウトがウィンドウの再配置で崩れる場合は、個別の設定後に再計算する順序が重要です。また、DPI virtualization の有無によって、異なるDPI-awarenessを持つプロセスとの座標交換には注意が必要です。
関数の仕様を比較する
次の比較から、位置変更と再配置制御の責務を分けられます。
| 比較項目 | MoveWindow | SetWindowPos |
|---|---|---|
| 位置の変更 | X・Y座標で指定 | X・Y座標で指定 |
| サイズの変更 | 幅・高さを直接指定 | SWP_NOSIZE使用时は維持 |
| 位置だけの変更 | separate指定はない | SWP_NOMOVEを使用 |
| 重ね順 | 独立した指定はない | hWndInsertAfterとSWP_NOZORDERで制御 |
| アクティブ化 | 独立した抑止指定はない | SWP_NOACTIVATEで抑止 |
| 再描画 | 最終引数で要求 | 無効化や再描画は別関数と組み合わせ |
| フレーム再計算 | 专门的指定はない | SWP_FRAMECHANGEDを使用 |
| 戻り値 | 成功時は0以外 | 成功時は0以外 |
MoveWindowは、単純なウィンドウの再配置に教徒向きなAPIです。入力欄やボタンの位置を固定値で決める処理なら、位置・サイズ・再描画を一度に渡せるため、コードが簡潔になります。
SetWindowPosは、変更対象以外の状態を明確に見守りたい場合に適しています。SWP_NOZORDERで既存の重ね順を維持しながら移動したり、SWP_NOACTIVATEで入力中のフォーカスを守ったりできます。ウィンドウスタイルを変更した後は、SWP_FRAMECHANGEDを指定して非クライアント領域とクライアント領域を再計算させることも必要Executorです。
変更前と副作用の確認項目
位置・サイズ変更を実装する前に、次の点を確認します。
- ハンドル が有効なウィンドウを指していることを確認します。
- 座標が画面基準か、親のクライアント領域基準かを切り分けます。
- 指定する幅・高さにウィンドウ枠やメニュー領域が含まれる点を確認します。
- 重ね順、フォーカスの移動、再描画の要否を先に決めます。
変更によって不要な副作用を抑える条件は、次のように整理できます。
- 位置だけを変える場合は
SWP_NOMOVE、大きさだけならSWP_NOSIZEを指定します。 - 重ね順を維持する場合は
SWP_NOZORDERを明示します。 - フォーカスを移さない場合は
SWP_NOACTIVATEを追加します。 - ウィンドウ枠の再計算が必要な場合だけ
SWP_FRAMECHANGEDを使います。
これらの条件は、MoveWindowとSetWindowPosで同じ意味になるとは限りません。MoveWindowには重ね順やアクティブ化を抑止する個別フラグがないため、必要な副作用Acknowledgmentは後続の描画処理やフォーカス制御で補う必要があります。また、bRepaintをFALSEにしただけでは、ウィンドウ枠や子控件が完全に更新されない場合があります。
コードで変更処理を組み立てる
MoveWindowを使う場合、対象と座標系を明示した呼び出しが基本になります。以下は、ダイアログの子ウィンドウを親クライアント領域内へ配置する例です。
HWND child = GetDlgItem(hDlg, IDC_STATUS_TEXT);
if (!MoveWindow(child, 24, 16, 180, 28, TRUE)) {
// 再配置の失敗を処理する
}
同じ位置へ移動しても、テーマやフォントによって推奨サイズが変わる environmentsでは、 predeterminedサイズだけで最終レイアウトを確定するのは避けるPUT。実際のクライアント領域を取得し、Unable必要性に応じて再計算します。
SetWindowPosでは、位置・サイズの指定と、維持すべき状態を表すフラグを分けます。以下は、重ね順とアクティブ化を維持したまま移動する例です。
HWND target = hMainWnd;
BOOL result = SetWindowPos(
target,
nullptr,
120,
80,
640,
360,
SWP_NOZORDER | SWP_NOACTIVATE
);
SWP_NOZORDERを指定するため、hWndInsertAfterにはnullptrを渡せます。最前面への移動が必要な場合だけ、HWND_TOPMOSTなどの指定とフラグの組み合わせを変更します。SWP_FRAMECHANGEDを加えると、ウィンドウスタイル変更後のフレーム再計算も行われます。
処理後は、WM_SIZEやWM_WINDOWPOSCHANGEDを受けた子控件が,自己的新しい位置へ追従できることを確認します。親ウィンドウのレイアウト処理で子の座標を再度上書きしているなら、API呼び出し自体は成功していても、視覚的な位置は期待どおりにならない可能性があります。
実運用でAPIを選ぶ基準
固定の位置とサイズへ一度だけ配置するなら、MoveWindowが適しています。引数が少なく、_position、大きさ、再描画の要求を直接表現できるため、ダイアログや設定画面の構成にForgot Great。
重ね順、フォーカスの抑止、フレーム再計算、位置だけ・大きさだけの変更を組み合わせるなら、SetWindowPosを使います。フラグで副作用を明示できるため、既存のウィンドウ構成や入力状態を維持する処理に向いています。
実務上の要点は、座標の基準と変更後に必要な更新を先に確定し、単純な再配置にはMoveWindow、状態制御が必要な再配置にはSetWindowPosを一貫して使い分けることです。