博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
控件布局通用解决方案
阅读量:4361 次
发布时间:2019-06-07

本文共 6791 字,大约阅读时间需要 22 分钟。

你是否遇到过这样的问题:用编译器拖出一些控件放到对话框上,并合理安排好了位置;但编译运行,改变对话框的大小后,所有控件的位置都乱了,让人感觉非常糟糕。如果控件不太多,你可以尝试手写代码定位每个控件的位置,但若是控件数量以十或百为单位计数甚至更多,逐一为每个控件指定位置就非常麻烦了。

本文提供一个宏,可以按照通常对话框的布局要求快速为每个控件布局,对话框大小改变时,控件的大小和位置都会随之而改变。改变控件位置和大小的代码都在宏内部,你只需了解宏的作用即可达到所需布局。

注意,编写宏和测试环境为XP + VC++6.0SP6 + MFC,其他编译环境可能需对宏稍加修改,我相信你有这个实力。

 

// CtrlId           : 控件ID// LeftChangeMode   : 0:与窗口客户区左边的距离不变; 1:按比例变化; 2:保持控件宽度不变;// RightChangeMode  : 0:与窗口客户区右边的距离不变; 1:按比例变化; 2:保持控件宽度不变;// TopChangeMode    : 0:与窗口客户区上边的距离不变; 1:按比例变化; 2:保持控件高度不变;// BottomChangeMode : 0:与窗口客户区下边的距离不变; 1:按比例变化; 2:保持控件高度不变;#ifndef AUTO_SET_CONTROL_POS// LeftChangeMode取值宏定义#define LEFT_CHANGE_MODE_FIXED_LEFTPADDING    0#define LEFT_CHANGE_MODE_RATIO                1#define LEFT_CHANGE_MODE_FIXED_WIDTH          2// RightChangeMode取值宏定义#define RIGHT_CHANGE_MODE_FIXED_RIGHTPADDING  0#define RIGHT_CHANGE_MODE_RATIO               1#define RIGHT_CHANGE_MODE_FIXED_WIDTH         2// TopChangeMode取值宏定义#define TOP_CHANGE_MODE_FIXED_TOPPADDING      0#define TOP_CHANGE_MODE_RATIO                 1#define TOP_CHANGE_MODE_FIXED_HEIGHT          2// BottomChangeMode取值宏定义#define BOTTOM_CHANGE_MODE_FIXED_LEFEPADDING  0#define BOTTOM_CHANGE_MODE_RATIO              1#define BOTTOM_CHANGE_MODE_FIXED_HEIGHT       2#define AUTO_SET_CONTROL_POS(CtrlId, LeftChangeMode, RightChangeMode, TopChangeMode, BottomChangeMode)\{\	static int   nFirstCtrlId = -1;\	static CRect rectLastClientWindow;\	static CRect rectLastClientWindowTmp;\	if (-1 == nFirstCtrlId)\	{\		nFirstCtrlId = CtrlId;\	}\	if (nFirstCtrlId == CtrlId)\	{\		rectLastClientWindowTmp = rectLastClientWindow;\	}\	rectLastClientWindow.right = cx;\	rectLastClientWindow.bottom = cy;\	CWnd *pWndDlgItem = GetDlgItem(CtrlId);\	if (pWndDlgItem)\	{\		CRect rectDlgItem;\		pWndDlgItem->GetWindowRect(rectDlgItem);\		ScreenToClient(rectDlgItem);\		\		static int   nDefaultLeftPadding_##CtrlId  =  rectDlgItem.left;\		static float fDefaultLeftRatio_##CtrlId    = (float)rectDlgItem.left\			/ rectLastClientWindowTmp.right;\		static int   nDefaultRightPadding_##CtrlId =  rectLastClientWindowTmp.right\			- rectDlgItem.right;\		static float fDefaultRightRatio_##CtrlId   = (float)rectDlgItem.right\			/ rectLastClientWindowTmp.right;\		static int   nDefaultCtrlWidth_##CtrlId    =  rectDlgItem.right - rectDlgItem.left;\		int          nXChangeMode = (LeftChangeMode << 8) + RightChangeMode;\		\		static int   nDefaultTopPadding_##CtrlId    =  rectDlgItem.top;\		static float fDefaultTopRatio_##CtrlId      = (float)rectDlgItem.top\			/ rectLastClientWindowTmp.bottom;\		static int   nDefaultBottomPadding_##CtrlId =  rectLastClientWindowTmp.bottom\			- rectDlgItem.bottom;\		static float fDefaultBottomRatio_##CtrlId   = (float)rectDlgItem.bottom\			/ rectLastClientWindowTmp.bottom;\		static int   nDefaultCtrlHeight_##CtrlId    =  rectDlgItem.bottom - rectDlgItem.top;\		int          nYChangeMode = (TopChangeMode << 8) + BottomChangeMode;\		\		if (0x0000 == nXChangeMode)\		{\			rectDlgItem.right = cx - nDefaultRightPadding_##CtrlId;\		}\		else if (0x0001 == nXChangeMode)\		{\			rectDlgItem.right = fDefaultRightRatio_##CtrlId * cx;\		}\		else if (0x0002 == nXChangeMode)\		{\			/*这里不用更改*/\		}\		else if (0x0100 == nXChangeMode)\		{\			rectDlgItem.left = fDefaultLeftRatio_##CtrlId * cx;\			rectDlgItem.right = cx - nDefaultRightPadding_##CtrlId;\		}\		else if (0x0101 == nXChangeMode)\		{\			rectDlgItem.left = fDefaultLeftRatio_##CtrlId * cx;\			rectDlgItem.right = fDefaultRightRatio_##CtrlId * cx;\		}\		else if (0x0102 == nXChangeMode)\		{\			rectDlgItem.left = fDefaultLeftRatio_##CtrlId * cx;\			rectDlgItem.right = rectDlgItem.left + nDefaultCtrlWidth_##CtrlId;\		}\		else if (0x0200 == nXChangeMode)\		{\			rectDlgItem.right = cx - nDefaultRightPadding_##CtrlId;\			rectDlgItem.left = rectDlgItem.right - nDefaultCtrlWidth_##CtrlId;\		}\		else if (0x0201 == nXChangeMode)\		{\			rectDlgItem.right = fDefaultRightRatio_##CtrlId * cx;\			rectDlgItem.left = rectDlgItem.right - nDefaultCtrlWidth_##CtrlId;\		}\		else if (0x0202 == nXChangeMode)\		{\			/*这里不用更改*/\		}\		\		\		if (0x0000 == nYChangeMode)\		{\			rectDlgItem.bottom = cy - nDefaultBottomPadding_##CtrlId;\		}\		else if (0x0001 == nYChangeMode)\		{\			rectDlgItem.bottom = fDefaultBottomRatio_##CtrlId * cy;\		}\		else if (0x0002 == nYChangeMode)\		{\			/*这里不用更改*/\		}\		else if (0x0100 == nYChangeMode)\		{\			rectDlgItem.top = fDefaultTopRatio_##CtrlId * cy;\			rectDlgItem.bottom = cy - nDefaultBottomPadding_##CtrlId;\		}\		else if (0x0101 == nYChangeMode)\		{\			rectDlgItem.top = fDefaultTopRatio_##CtrlId * cy;\			rectDlgItem.bottom = fDefaultBottomRatio_##CtrlId * cy;\		}\		else if (0x0102 == nYChangeMode)\		{\			rectDlgItem.top = fDefaultTopRatio_##CtrlId * cy;\			rectDlgItem.bottom = rectDlgItem.top + nDefaultCtrlHeight_##CtrlId;\		}\		else if (0x0200 == nYChangeMode)\		{\			rectDlgItem.bottom = cy - nDefaultBottomPadding_##CtrlId;\			rectDlgItem.top = rectDlgItem.bottom - nDefaultCtrlHeight_##CtrlId;\		}\		else if (0x0201 == nYChangeMode)\		{\			rectDlgItem.bottom = fDefaultBottomRatio_##CtrlId * cy;\			rectDlgItem.top = rectDlgItem.bottom - nDefaultCtrlHeight_##CtrlId;\		}\		else if (0x0202 == nYChangeMode)\		{\			/*这里不用更改*/\		}\		pWndDlgItem->MoveWindow(rectDlgItem);\	}\}#endif

使用时,只需在对话框的WM_SIZE消息处理函数中加上“AUTO_SET_CONTROL_POS(CtrlId, LeftChangeMode, RightChangeMode, TopChangeMode, BottomChangeMode)”即可,各个参数含义见宏定义的头部注释。对话框大小改变,就会自动修改指定控件的位置和大小。

 

上图是测试中MFC控件初化的位置,下图为修改控件大小后的布局:

代码中所作的处理如下:

 

void CDialogApplicationDlg::OnSize(UINT nType, int cx, int cy) {	CDialog::OnSize(nType, cx, cy);			AUTO_SET_CONTROL_POS(    IDC_EDIT1, LEFT_CHANGE_MODE_FIXED_LEFTPADDING, 		RIGHT_CHANGE_MODE_FIXED_RIGHTPADDING, 		TOP_CHANGE_MODE_FIXED_TOPPADDING, 		BOTTOM_CHANGE_MODE_FIXED_HEIGHT);	AUTO_SET_CONTROL_POS(IDC_RICHEDIT1, LEFT_CHANGE_MODE_FIXED_LEFTPADDING, 		RIGHT_CHANGE_MODE_FIXED_RIGHTPADDING, 		TOP_CHANGE_MODE_FIXED_TOPPADDING, 		BOTTOM_CHANGE_MODE_FIXED_LEFEPADDING);	AUTO_SET_CONTROL_POS(         IDOK, LEFT_CHANGE_MODE_FIXED_WIDTH, 		RIGHT_CHANGE_MODE_FIXED_RIGHTPADDING, 		TOP_CHANGE_MODE_FIXED_TOPPADDING, 		BOTTOM_CHANGE_MODE_FIXED_HEIGHT);	AUTO_SET_CONTROL_POS(     IDCANCEL, LEFT_CHANGE_MODE_FIXED_WIDTH, 		RIGHT_CHANGE_MODE_FIXED_RIGHTPADDING, 		TOP_CHANGE_MODE_FIXED_TOPPADDING, 		BOTTOM_CHANGE_MODE_FIXED_HEIGHT);	AUTO_SET_CONTROL_POS(   IDC_STATIC, LEFT_CHANGE_MODE_FIXED_LEFTPADDING,		RIGHT_CHANGE_MODE_FIXED_WIDTH, 		TOP_CHANGE_MODE_FIXED_HEIGHT, 		BOTTOM_CHANGE_MODE_FIXED_LEFEPADDING);	AUTO_SET_CONTROL_POS(  IDC_BUTTON1, LEFT_CHANGE_MODE_FIXED_WIDTH, 		RIGHT_CHANGE_MODE_FIXED_RIGHTPADDING, 		TOP_CHANGE_MODE_FIXED_HEIGHT, 		BOTTOM_CHANGE_MODE_FIXED_LEFEPADDING);}

每个控件调用一次AUTO_SET_CONTROL_POS,各个参数以宏的形式提供,非常容易了解,比起手写代码非常清晰。当然,如果想重新设计各个控件的布局,只需重新指定布局参数即可。

 

 

转载于:https://www.cnblogs.com/snake-hand/p/3149578.html

你可能感兴趣的文章
[算法练习]Excel Sheet Column Title
查看>>
【原创】MapReduce编程系列之表连接
查看>>
IOS开发之Swift学习笔记
查看>>
【Java基础】用LinkedList实现一个简单栈的功能
查看>>
线段树C-A Simple Problem with Integers(树懒线段树)
查看>>
Ferguson游戏
查看>>
PHPExcel
查看>>
create your own github repository and build link to your local project
查看>>
Leetcode-Convert Sorted Array to BST
查看>>
form表单,submit,ajax提交
查看>>
三大平衡树(Treap + Splay + SBT)总结+模板
查看>>
关于数据库名、实例名
查看>>
多线程不安全的函数列表
查看>>
Codeforces Round #318 (Div. 2) B Bear and Three Musketeers (暴力)
查看>>
SVN+AnkhSVN端配置
查看>>
mysql慢查询工具
查看>>
socket代码
查看>>
HTML5 之 简单汇总
查看>>
C#中结构体定义并转换字节数组
查看>>
前端进阶路线图
查看>>