2018年10月15日月曜日

マルチディスプレイ環境で親ウィンドウの中心にウィンドウを表示するには

表題の通りです。

親ウィンドウの中央にダイアログなどを表示しようとすると、親ウィンドウそのものが画面から外れている場合に表示領域外に表示されてしまったりして困ったことになります。

マルチディスプレイ環境だったりすると、座標域に負数が含まれる場合などもあって、なかなかややこしい。

WEB上を検索しても、GetSystemMetrics(SM_CXSCREEN)とかGetSystemMetrics(SM_CXSFULLCREEN) などを使ったサンプルしか公開されていなくて、ちょっと不満だったので書いてみました。

ま、実際にはもっとややこしい環境もあると思うので完全ではないかもしれないけど、うちの環境では表示されるのでよしとしようw

ヘッダファイルの記述

extern BOOL SetWindowCenterParent(HWND handle, HWND parent, int width, int height, int min_width = -1, int min_heigh = -1);

ソースファイル

#include 
//
// ウィンドウを親ウィンドウの中心に表示する
//
// 【パラメータ】
//  HWND handle     対象となるウィンドウハンドル
//  HWND parent     親ウィンドウハンドル(HWND_DESKTOP も可)
//  int width       ウィンドウの幅
//  int height      ウィンドウの高さ
//  int min_width   最小ウィンドウ幅(不要な場合は負数を指定)
//  int min_heigh   最小ウィンドウ高さ(不要な場合は負数を指定)

BOOL SetWindowCenterParent(HWND handle, HWND parent, int width, int height, int min_width, int min_heigh)
{
 // 親ウィンドウの中心を取得
 RECT parent_rect;
 GetWindowRect(parent, &parent_rect);

 POINT center;
 center.x = (parent_rect.right + parent_rect.left) / 2;
 center.y = (parent_rect.bottom + parent_rect.top) / 2;

 // ディスプレイ情報
 SIZE display;
 display.cx = GetSystemMetrics(SM_CXVIRTUALSCREEN);
 display.cy = GetSystemMetrics(SM_CYVIRTUALSCREEN);
 
 // タスクバーの大きさを調整
 SIZE screen;
 screen.cx = GetSystemMetrics(SM_CXSCREEN);
 screen.cy = GetSystemMetrics(SM_CYSCREEN);
 RECT work_area;
 SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0);
 SIZE task_bar;
 task_bar.cx = screen.cx - (work_area.right - work_area.left);
 task_bar.cy = screen.cy - (work_area.bottom - work_area.top);
 display.cx -= task_bar.cx;
 display.cy -= task_bar.cy;

 POINT origin;
 origin.x = GetSystemMetrics(SM_XVIRTUALSCREEN);
 origin.y = GetSystemMetrics(SM_YVIRTUALSCREEN);

 // 最小サイズ、最大サイズの検査
 if ((0 < min_width) && (width < min_width))
 {
  width = min_width;
 }
 if ((0 < min_heigh) && (height < min_heigh))
 {
  height = min_heigh;
 }
 if (display.cx < width)
 {
  width = display.cx;
 }
 if (display.cy < height)
 {
  height = display.cy;
 }
 // 表示位置
 POINT place;
 place.x = center.x - (width / 2);
 place.y = center.y - (height / 2);

 // ディスプレイの座標範囲(マルチディスプレイ含む)からのはみだし検査
 if ((origin.x + display.cx) < (place.x + width))
 {
  place.x = origin.x + display.cx - width;
 }
 if (place.x < origin.x)
 {
  place.x = origin.x;
 }
 if ((origin.y + display.cy) < (place.y + height))
 {
  place.y = origin.y + display.cy - height;
 }
 if (place.y < origin.y)
 {
  place.y = origin.y;
 }
 return SetWindowPos(handle, HWND_TOP, place.x, place.y, width, height, 0);
}