C++ Builder > UtilWindowLocation > メインウィンドウの位置を９等分(3x3)のいずれかにする

```txt:動作環境
C++ Builder XE4
```

### 背景

複数のソフトを起動するとウィンドウが重なるが、XE4ではソフトの位置は以下のような選択肢しかない。

- as designed
- 中央 (画面、メインウィンドウ、etc)

だいたい9つの位置にメインウィンドウを配置する処理を作ってみた。

### code v0.1

```UtilWindowLocation.h
//---------------------------------------------------------------------------

#ifndef UtilWindowLocationH
#define UtilWindowLocationH

//---------------------------------------------------------------------------

/*
ソフトのメイン画面の位置調整用
厳密な調整ではなく、複数ソフト起動時に重なりを軽減する
*/

class CUtilWindowLocation {
private:
public:
	enum {
		V_AS_IT_IS, // 変更しない
		V_TOP,
		V_CENTER,
		V_BOTTOM,
	};
	enum {
		H_AS_IT_IS, // 変更しない
		H_LEFT,
		H_CENTER,
		H_RIGHT,
	};
	static void __fastcall SetLocation(TForm *targetPtr, int vindex, int hindex);
	static void __fastcall Test_SetLocation(TForm *targetPtr);
};

#endif
```

```UtilWindowLocation.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "UtilWindowLocation.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

/*
v0.1 2017/10/25
	- Test_SetLocation()追加
	- SetLocation()追加
*/

/*static*/void __fastcall CUtilWindowLocation::SetLocation(TForm *targetPtr, int vindex, int hindex)
{
	if (targetPtr == NULL) {
        return; // error
	}

	targetPtr->Position = poDesigned; // Topなど位置変更を有効にするため

	int mnttop = Screen->Monitors[0]->Top;
	int mntleft = Screen->Monitors[0]->Left;

	switch(vindex) {
	case V_TOP:
		targetPtr->Top = mnttop;
		break;
	case V_CENTER:
		targetPtr->Top = mnttop + Screen->Monitors[0]->Height * 1 / 3;
		break;
	case V_BOTTOM:
		targetPtr->Top = mnttop + Screen->Monitors[0]->Height * 2 / 3;
		break;
	}

	switch(hindex) {
	case H_LEFT:
		targetPtr->Left = mntleft;
		break;
	case H_CENTER:
		targetPtr->Left = mntleft + Screen->Monitors[0]->Width * 1 / 3;
		break;
	case H_RIGHT:
		targetPtr->Left = mntleft + Screen->Monitors[0]->Width * 2 / 3;
		break;
	}
}

/*static*/void __fastcall CUtilWindowLocation::Test_SetLocation(TForm *targetPtr)
{
	/*
	実際の使用では、コンストラクタなどにSetLocation()をコールする
	FormShow時に実行するとエラーになる。
	*/

	int hlist[] = { H_AS_IT_IS, H_LEFT, H_CENTER, H_RIGHT };
	int vlist[] = { V_AS_IT_IS, V_TOP, V_CENTER, V_BOTTOM };
	int numh = sizeof(hlist) / sizeof(hlist[0]);
	int numv = sizeof(vlist) / sizeof(vlist[0]);

	for(int hidx=0; hidx < numh; hidx++) {
		for(int vidx=0; vidx < numv; vidx++) {
			SetLocation(targetPtr, vlist[vidx], hlist[hidx]);
			//
			Application->ProcessMessages();
			Sleep(1000);
		}
	}

}
```

### 使用例

Test_SetLocation()の実装を参考にCUtilWindowLocation::SetLocation()を使う。
~~FormShow時にはApplication->ProcessMessage()とSleep()は不要。~~
(**FormShow時にはエラーとなるので、コンストラクタや別のタイミングで実施する**)
Application->ProcessMessage()とSleep()はButtonClickイベント内での処理として使っているだけ。

試しに、以下のテスト実行をすると、ウィンドウが移動していく。

```cpp
void __fastcall TFormMain::Button1Click(TObject *Sender)
{
	CUtilWindowLocation::Test_SetLocation(this);
}
```

### 位置調整

位置調整を頑張りすぎると、モニタサイズ変更時におかしな配置になるだろう。

上記のような大雑把な調整とした。

### 関連

[SketchUp Make v17 / Ruby > 複数のGroupを整列する > X方向](https://qiita.com/7of9/items/7400ebcbbfa10cacefaa)

[Unity > ScreenSizeKeeper](https://github.com/yasokada/unity-160820-Inventory-UI/blob/master/Assets/ScreenSizeKeeper.cs)