zoukankan      html  css  js  c++  java
  • 控件布局通用解决方案

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

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

    注意,编写宏和测试环境为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,各个参数以宏的形式提供,非常容易了解,比起手写代码非常清晰。当然,如果想重新设计各个控件的布局,只需重新指定布局参数即可。



  • 相关阅读:
    Linux下防火墙的相关命令
    java中的异常总结
    Java中的==和equals的区别
    一个简单的前后端分离项目,适合新手练手
    入住博客园鸭
    centos7 安装 Python PIL模块
    Linux 装机错误解决
    Python 爬取煎蛋网妹子图片代码
    Python 简易聊天机器人
    Python员工信息表练习
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3149578.html
Copyright © 2011-2022 走看看