Win32控件自动布局管理

转载自 http://bbs.csdn.net/topics/380000840

通过句柄标识控件,MoveWindow函数进行布局

/*******************************************************************************
* Copyright:   2011-2012 by Arsaisy.lin
* File name:   LayoutManager.h
* Description: 布局管理器模块,用于管理MS Windows平台的桌面应用程序界面布局,兼
*              容由Win32API或MFC、ATL等与窗口句柄(HWND)相关的库创建的桌面界面程
*              序。本模块依赖于MS Platform SDK和标准C++STL。
*              本文件为免费资源,可以应用于开源、免费和商业等软件应用,不会收取
*              任何费用,但需要注明程序出处。
* Author:      Arsaisy.lin
* Contact:     arsaisy@126.com
* Version:     1.0
* Date:        2011/10/26
* History:     
*******************************************************************************/

#ifndef __LAYOUTMANAGER_H__
#define __LAYOUTMANAGER_H__

#include <Windows.h>
#include <list>
#include <vector>

namespace Win32Layout
{

/*******************************************************************************
* SizeType尺寸类型,布局中的占位方式。
*   PIXEL:      以像素方式占位
*   PERCENTAGE: 以比例方式占位
#   FILL:       以填充方式占位
*******************************************************************************/
enum SizeType {
	PIXEL,
	PERCENTAGE,
	FILL
};

/*******************************************************************************
* BoxType盒子类型,布局对象的对齐方式。
*   HORIZONTAL: 水平分布对象
*   VERTICAL:   垂直分布对象
*******************************************************************************/
enum BoxType {
	HORIZONTAL,
	VERTICAL
};

/*******************************************************************************
* LayoutObject布局对象类
*   LayoutObject类是所有可以进行布局类的基类,需要进行布局的类都需要继承此类。
*******************************************************************************/
class LayoutObject {
public:
	LayoutObject() :_w(0), _h(0), _stw(PIXEL), _sth(PIXEL) {}
	virtual ~LayoutObject() {}
	virtual void Layout(int x, int y, int w, int h) = 0;
	int GetW() { return _w; }
	int GetH() { return _h; }
	SizeType GetWST() { return _stw; }
	SizeType GetHST() { return _sth; }

	/*
	* SetSize函数,设置布局对象的尺寸和尺寸类型。
	*   w:   宽度
	*   h:   高度
	*   stw: 宽度尺寸类型
	*   sth: 高度尺寸类型
	*   宽度与高度由尺寸类型动态决定其大小。如果尺寸类型为像素PIXEL,宽度或高度
	* 表示实际的像素的大小;如果尺寸类型为比例PERCENTAGE,宽度或高度的大小表示
	* 总宽度或总高度的相应比例值;如果尺寸类型为FILL,宽度或高度则尽可能填充所有
	* 的剩余范围。
	*/
	void SetSize(int w, int h, SizeType stw, SizeType sth) {
		_w = w;
		_h = h;
		_stw = stw;
		_sth = sth;
	}

protected:
	int _w;
	int _h;
	SizeType _stw;
	SizeType _sth;
};


/*******************************************************************************
* Window窗口类,继承于LayoutObject类,负责调整窗口的位置。
*   通过构造函数与窗口句柄绑定,也可以创建对象后使用Attach与窗口句柄绑定。类销
* 毁时不会销毁窗口,不需要解除绑定。可以在使用过程中动态绑定其他窗口,但不建议
* 这样做。
*******************************************************************************/
class Window : public LayoutObject {
public:
	Window(HWND hWnd = NULL) { _hWnd = hWnd; }
	virtual ~Window() {}
	
	/*
	* Attach函数,与窗口句柄进行绑定。如果构造函数没有指定窗口句柄,可以在需要
	* 时调用此函数进行绑定。也可以不绑定,布局时不发生任何操作。
	*/
	void Attach(HWND hWnd) { _hWnd = hWnd; }

	/*
	* Handle函数,获取已经绑定的窗口句柄。
	*/
	HWND Handle() { return _hWnd; }

	/*
	* Layout布局函数,把对象放置在坐标(x, y),大小为w*h的范围内。对窗口类则简单
	* 的调用Win32API函数MoveWindow设置对象位置。
	*/
	void Layout(int x, int y, int w, int h) {
		if (::IsWindow(_hWnd))
			MoveWindow(_hWnd, x, y, w, h, TRUE);
	}

protected:
	/*
	* 窗口句柄,可以为NULL。
	*/
	HWND _hWnd;
};

/*******************************************************************************
* Box布局盒子类,本模块最重要的类,所有布局任务都由此类完成。
*   该类一般与WINDOWS消息共同使用。使用方法为1.创建该对象;2.调用AddWindow指派要
* 进行布局的窗口句柄或调用AddHBox、AddVBox增加嵌套的布局盒子;3.在需要的时候(如
# WM_SIZE消息)时调用盒子的Layout函数进行布局管理。
*/
class Box : public LayoutObject {
public:
	Box(BoxType boxType = HORIZONTAL) {
		_separatorSize = 3;
		_boxType = boxType;
	}

	virtual ~Box() {
		std::list<LayoutObject*>::iterator it = _sublist.begin();
		for (; it != _sublist.end(); it++)
			delete (*it);
		_sublist.clear();
	}

	/*
	* SetType函数,设置盒子的对齐方式,可以是水平或垂直。
	*/
	void SetType(BoxType boxType) {
		_boxType = boxType;
	}

	/*
	* SetSeparatorSize函数,设置分隔条大小,默认为3个像素。
	*/
	void SetSeparatorSize(int size) {
		_separatorSize = size;
	}

	/*
	* AddHBox函数,增加内嵌的水平盒子。
	*   增加时可以指定盒子的大小与对齐方式。增加完成后返回新增加的盒子,可以使用
	* 返回的盒子继续增加对象。由本函数创建的内嵌盒子不可以调用delete删除,它由系
	* 统自动回收。
	*/
	Box* AddHBox(int w, int h, SizeType stw, SizeType sth) {
		Box* box = new Box(HORIZONTAL);
		box->SetSize(w, h, stw, sth);
		_sublist.push_back(box);
		return box;
	}

	/*
	* AddVBox函数,增加内嵌的垂直盒子。
	*   功能与AddHBox功能类似。
	*/
	Box* AddVBox(int w, int h, SizeType stw, SizeType sth) {
		Box* box = new Box(VERTICAL);
		box->SetSize(w, h, stw, sth);
		_sublist.push_back(box);
		return box;
	}

	/*
	* AddWindow函数,增加需要布局的窗口。
	*   调用该函数增加一个需要进行布局的窗口句柄,同时指定大小与尺寸类型,并返回
	* 相应的窗口布局对象,可以保存方便以后更改大小。本函数创建的对象不可以调用
	* delete删除,它由系统自动回收。
	*/
	Window* AddWindow(HWND hWnd, int w, int h, SizeType stw, SizeType sth) {
		Window* window = new Window(hWnd);
		window->SetSize(w, h, stw, sth);
		_sublist.push_back(window);
		return window;
	}

	/*
	* Layout函数,布局已经指派的控件对象。
	*   把指定控件布局在坐标(x, y),w*h范围内。
	*/
	void Layout(int x, int y, int w, int h) {
		if (_boxType == HORIZONTAL)
			LayoutHorizontal(x, y, w, h);
		else
			LayoutVertical(x, y, w, h);
	}

protected:
	/*
	* LayoutHorizontal函数,水平调整控件位置
	*/
	void LayoutHorizontal(int x, int y, int w, int h) {
		int objCount = (int)_sublist.size();
		int spaceWidth = w - _separatorSize * (objCount - 1);
		int residualWidth = spaceWidth;
		int objx, objy, objw, objh;
		std::vector<int> wlist;
		std::vector<int> fillIndexs;

		if (spaceWidth <= 0)
			spaceWidth = 0;
		
		std::list<LayoutObject*>::iterator it = _sublist.begin();
		for (int index = 0; it != _sublist.end(); it++, index++) {
			LayoutObject* lo = (*it);

			if (lo->GetWST() == PIXEL) {
				objw = lo->GetW();
			} else if (lo->GetWST() == PERCENTAGE) {
				objw = (int)((double)spaceWidth * ((double)lo->GetW() / 100.0));
			} else if (lo->GetWST() == FILL) {
				objw = -1;
				fillIndexs.push_back(index);
			} else {
				objw = 0;
			}
			
			if (objw > residualWidth)
				objw = residualWidth;
			wlist.push_back(objw);
			residualWidth -= objw;
		}

		if (fillIndexs.size() > 0) {
			for (int i = 0; i < residualWidth; i++) {
				int index = i % (int)fillIndexs.size();
				wlist[fillIndexs[index]] += 1;
			}
		}

		objx = x;
		objy = y;
		it = _sublist.begin();
		for (int index = 0; it != _sublist.end(); it++, index++) {
			LayoutObject* lo = (*it);
			objw = wlist[index];

			if (lo->GetHST() == PIXEL) {
				objh = lo->GetH();
			} else if (lo->GetHST() == PERCENTAGE) {
				objh = (int)((double)h * ((double)lo->GetH() / 100.0));
			} else if (lo->GetHST() == FILL) {
				objh = h;
			}
			if (objh > h)
				objh = h;

			lo->Layout(objx, objy, objw, objh);

			objx += objw;
			objx += _separatorSize;
		}
	}

	/*
	* LayoutHorizontal函数,垂直调整控件位置
	*/
	void LayoutVertical(int x, int y, int w, int h) {
		int objCount = (int)_sublist.size();
		int spaceHeight = h - _separatorSize * (objCount - 1);
		int residualHeight = spaceHeight;
		int objx, objy, objw, objh;
		std::vector<int> hlist;
		std::vector<int> fillIndexs;

		if (spaceHeight <= 0)
			spaceHeight = 0;
		
		std::list<LayoutObject*>::iterator it = _sublist.begin();
		for (int index = 0; it != _sublist.end(); it++, index++) {
			LayoutObject* lo = (*it);

			if (lo->GetHST() == PIXEL) {
				objh = lo->GetH();
			} else if (lo->GetHST() == PERCENTAGE) {
				objh = (int)((double)spaceHeight * ((double)lo->GetH() / 100.0));
			} else if (lo->GetHST() == FILL) {
				objh = -1;
				fillIndexs.push_back(index);
			} else {
				objh = 0;
			}
			
			if (objh > residualHeight)
				objh = residualHeight;
			hlist.push_back(objh);
			residualHeight -= objh;
		}

		if (fillIndexs.size() > 0) {
			for (int i = 0; i < residualHeight; i++) {
				int index = i % (int)fillIndexs.size();
				hlist[fillIndexs[index]] += 1;
			}
		}

		objx = x;
		objy = y;
		it = _sublist.begin();
		for (int index = 0; it != _sublist.end(); it++, index++) {
			LayoutObject* lo = (*it);
			objh = hlist[index];

			if (lo->GetWST() == PIXEL) {
				objw = lo->GetW();
			} else if (lo->GetWST() == PERCENTAGE) {
				objw = (int)((double)h * ((double)lo->GetW() / 100.0));
			} else if (lo->GetWST() == FILL) {
				objw = w;
			} else {
				objw = 0;
			}
			if (objw > w)
				objw = w;

			lo->Layout(objx, objy, objw, objh);

			objy += objh;
			objy += _separatorSize;
		}
	}

protected:
	std::list<LayoutObject*> _sublist; /*对象列表*/
	int _separatorSize;                /*分隔条大小*/
	BoxType _boxType;                  /*盒子类型*/
};

}

#endif


使用方法:

1、在OnInitDialog中加入布局设置:

	// 初始化布局
	m_layout.SetType(Win32Layout::VERTICAL);

	Win32Layout::Box* box1 = m_layout.AddHBox(0, 0, Win32Layout::FILL, Win32Layout::FILL);
	box1->AddWindow(::GetDlgItem(m_hWnd, IDC_TREE1), 0, 0, Win32Layout::FILL, Win32Layout::FILL);
	box1->AddWindow(::GetDlgItem(m_hWnd, IDC_LIST1), 0, 0, Win32Layout::FILL, Win32Layout::FILL);
	box1->AddWindow(::GetDlgItem(m_hWnd, IDC_LIST2), 0, 0, Win32Layout::FILL, Win32Layout::FILL);
	
	m_layout.AddWindow(::GetDlgItem(m_hWnd, IDC_EDIT1), 0, 100, Win32Layout::FILL, Win32Layout::PIXEL);
	
	Win32Layout::Box* box2 = m_layout.AddHBox(0, 20, Win32Layout::FILL, Win32Layout::PIXEL);
	box2->AddWindow(::GetDlgItem(m_hWnd, IDC_CHECK1), 50, 0, Win32Layout::PIXEL, Win32Layout::FILL);
	box2->AddWindow(::GetDlgItem(m_hWnd, IDC_CHECK2), 50, 0, Win32Layout::PIXEL, Win32Layout::FILL);

	Win32Layout::Box* box3 = m_layout.AddHBox(0, 20, Win32Layout::FILL, Win32Layout::PIXEL);
	box3->AddWindow(::GetDlgItem(m_hWnd, IDC_EDIT2), 0, 0, Win32Layout::FILL, Win32Layout::FILL);
	box3->AddWindow(::GetDlgItem(m_hWnd, IDC_BUTTON1), 80, 0, Win32Layout::PIXEL, Win32Layout::FILL);

2、在OnSize中加入

m_layout.Layout(3, 3, cx - 6, cy - 6);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值