ウィンドウのサイズ変更に合わせてコントロールのサイズを変更する

**アカウント統合により過去記事再掲：元の投稿日  2016年03月29日**


# 例えばダイアログのサイズを変更した時
![image](https://qiita-image-store.s3.amazonaws.com/0/104780/be1176a4-7f48-49c8-284c-c985b9f0b708.png)
↓サイズ変更すると・・・
![image](https://qiita-image-store.s3.amazonaws.com/0/104780/d5cd31c6-2d7d-257b-1c4a-1d180cd697fc.png)

あらあら、まあまあ。

C#なんかは↓こういうアンカーがあって便利なのに。
![image](https://qiita-image-store.s3.amazonaws.com/0/104780/b2f8435e-2ba7-4358-5905-0c87b832ccb2.png)

というわけで久々にMFCを触ってて、そういや昔これに対応するクラス作ったなーと。VC++6の時なんだけど。

引っ張りだして使ってみたら、今でも普通に使えたんでQiitaにでも貼り付けとこうというお話。

# Doxygenが懐かしい
コメントの**@brief**とかはDoxygenというドキュメンテーションツールで、そういや使ってたなーと懐かしんでおりましたとさ。

```cpp:stratchControl.hpp
/** @file StretchControl.hpp
	@brief CStretchControl 定義ファイル
*/
#ifndef __STRETCHCONTROL_HPP__
#define __STRETCHCONTROL_HPP__

/**
	@class CStretchControl
	@brief 親ウィンドウ(通常はダイアログ)の伸縮にあわせて、伸縮(または移動)するウィンドウのテンプレートクラス
	@param T 適用するウィンドウ(TはCWndの派生クラスである必要があります)
	@par 概要:
	<BR>
	親ウィンドウ(通常はダイアログ)の伸縮にあわせて、伸縮(または移動)するウィンドウの
	テンプレートクラス

	@par 使い方:
	<BR>
		伸縮(移動)するウィンドウはサブクラス化をサブクラス化します。<BR>
		親ウィンドウが WM_SIZE を受信した時に、このクラスの Resizeメソッドを呼び出し
		て下さい。

	@par 例:
	<BR>
		ダイアログのエディットコントロールを対象とする場合<BR>
<BR>
		1) C***Dlg に CStretchControl<CEdit>型のメンバ変数を追加<BR>
		2) OnInitDialogで SubclassDlgItem を呼び出す<BR>
		3) OnSize を実装し、Resizeを呼び出す<BR>
*/
template<class T>
class CStretchControl : public T
{
	/** @brief 差分を格納する矩形 */
	CRect m_rectDiff;

	/** @brief 伸縮タイプ */
	UINT  m_baseType;

	/** @brief 保持された幅 */
	LONG  m_width;

	/** @brief 保持された高さ */
	LONG  m_height;

public:
	enum {
		normal = 0x00,
		top    = 0x01,
		left   = 0x02,
		bottom = 0x04,
		right  = 0x08,
	};

	/** @brief 標準のコンストラクタ */
	CStretchControl() : T(), m_baseType( 0 ), m_width( 0 ), m_height( 0 ) {
	}

protected:
	/** @brief SubclassWindow を呼び出す前にサブクラス化することを許します */
	virtual void PreSubclassWindow() {
		CRect rect, me;
		GetParent()->GetClientRect( &rect );
		
		GetWindowRect( &me );

		m_width  = me.Width();
		m_height = me.Height();

		GetParent()->ScreenToClient( &me );

		m_rectDiff.top    = me.top    - rect.top;
		m_rectDiff.left   = me.left   - rect.left;
		m_rectDiff.bottom = me.bottom - rect.bottom;
		m_rectDiff.right  = me.right  - rect.right;
	}

public:
	/** @brief 伸縮タイプに従ってサイズ変更を実施します */
	void Resize() {
		if( !m_hWnd ) {
			return;
		}
		CRect rect, me;

		GetParent()->GetClientRect( &rect );

		me.top    = rect.top    + m_rectDiff.top;
		me.left   = rect.left   + m_rectDiff.left;
		me.bottom = rect.bottom + m_rectDiff.bottom;
		me.right  = rect.right  + m_rectDiff.right;

		if( m_baseType & top    ) { me.bottom = me.top    + m_height; }
		if( m_baseType & left   ) { me.right  = me.left   + m_width;  }
		if( m_baseType & bottom ) { me.top    = me.bottom - m_height; }
		if( m_baseType & right  ) { me.left   = me.right  - m_width;  }

		MoveWindow( &me );

		InvalidateRect( NULL );
	}

	/** @brief 伸縮タイプを設定します 
		@param ui IN 伸縮タイプ
		@par 解説
			引数 ui には次の値を連結して指定します<BR>
		<BR>
			normal = 0x00	標準の伸縮をサポートします<BR>
			top    = 0x01	上を基点として上下には移動のみを行います<BR>
			left   = 0x02,	左を基点として左右には移動のみを行います<BR>
			bottom = 0x04,	下を基点として上下には移動のみを行います<BR>
			right  = 0x08,	右を基点として左右には移動のみを行います<BR>
		<BR>
			top, bottom の何れかが指定された場合、ウィンドウは最初の高さを保持します。<BR>
			left, right の何れかが指定された場合、ウィンドウは最初の幅を保持します。<BR>
	*/
	void setBase( UINT ui ) {
		m_baseType = ui;
	}

	/** @brief 伸縮タイプ基点を左下に設定します
	*/
	void setBase_BottomLeft() {
		m_baseType = bottom | left;
	}

	/** @brief 伸縮タイプ基点を下に設定します */
	void setBase_Bottom() {
		m_baseType = bottom;
	}

	/** @brief 伸縮タイプ基点を右下に設定します
	*/
	void setBase_BottomRight() {
		m_baseType = bottom | right;
	}

	/** @brief 伸縮タイプ基点を右に設定します */
	void setBase_Right() {
		m_baseType = right;
	}
};

#endif // __STRETCHCONTROL_HPP__
```
# 使い方
コメントに書いてある通りなんだけど、

・C***Dlg に CStretchControl<CEdit>型のメンバ変数を追加
・OnInitDialogで SubclassDlgItem を呼び出す
・OnSizeでResizeを呼び出す

これだけ。
お手軽。
もしクラスウィザードからCEditとかのコントロール変数を追加した場合は、自分でSubclassDlgItemを呼び出す必要はナッシング。
`CEdit m_hoge;`
↓
`CStretchControl<CEdit> m_hoge;`
こんな感じにするだけでよろしい。

ほんで、WM_SIZEをハンドリングして、
![image](https://qiita-image-store.s3.amazonaws.com/0/104780/2a92c991-146d-13eb-7edb-aeb2de3a9a74.png)

m_hoge.Resize();を呼び出すだけ。
![image](https://qiita-image-store.s3.amazonaws.com/0/104780/b833c2db-a8fe-e3ef-4a0e-3963720d79ef.png)

# びよーん
![image](https://qiita-image-store.s3.amazonaws.com/0/104780/35b5ff59-4529-4c45-1f53-0a2e5223c76d.png)