控件布局通用解决方案

article/2025/11/9 16:45:23

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

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

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




http://chatgpt.dhexx.cn/article/jmukGKhZ.shtml

相关文章

app基本控件

一个完整的APP包括四大类&#xff1a;各种“栏”&#xff1b;内容视图&#xff1b;控制元素&#xff1b;临时视图。 各种“栏”&#xff1a;状态栏、导航栏、标签栏、工具栏、搜索栏、范围栏。 内容视图&#xff1a;列表视图、卡片视图、集合视图、图片视图、文本视图。 控制…

应用程序界面开发 - 自定义用户控件布局控件的使用

在很多时候&#xff0c;我们做一些非常规化的界面的时候&#xff0c;往往需要创建一些用户控件&#xff0c;在其中绘制好一些基础的界面块&#xff0c;作为后续重复使用的一个单元&#xff0c;用户控件同时也可以封装处理一些简单的逻辑。在开发Winform各种类型项目&#xff0c…

控件

1. 自定义控件&#xff1a; 编写一个类继承自一个控件类&#xff1a; public class MyTextView extends TextView 在xml布局文件中声明控件为这种自定义的空间&#xff0c;注意一定要加上包名 <zy.qiufo.MyTextView android:id"id/tvJW" …… /> 代…

两款工控控件对比评测:Iocomp和ProEssentials

备注&#xff1a;本文章转载自慧都控件网 概述&#xff1a;使用专业的第三方控件开发漂亮逼真的工控仪表和图表是明智的选择&#xff0c;笔者对两款最好用的工控控件 Iocomp 和 ProEssentials进行了简单的对比评测。 对于程序员来说&#xff0c;要凭一己之力开发出漂亮逼真的工…

Spring Boot Actuator 使用介绍

Spring Boot Actuator 使用介绍 初识 Actuator原生端点应用配置类度量指标类 操作控制类 近期在看《Spring Cloud 微服务实战》&#xff0c;由于时间过去几年&#xff0c;对于Actuator监控端点的介绍过时&#xff0c;故作此文更新一下。 Spring Boot 版本&#xff1a;2.5.3 初识…

Activiti集成Activiti Modeler

Activiti6.0.0及以上版本与activiti-modeler的maven引用有冲突&#xff0c;解决方法参考Activiti6.0.0及以上版本集成Activiti Modeler 1.下载源文件 activiti-5.22.0官方Demo activiti5.22.0源码 2.copy源文件 &#xff08;一&#xff09;复制前端文件 解压activiti-5.22.…

【activiti】activiti入门

activiti入门 在本章内容中&#xff0c;我们来创建一个Activiti工作流&#xff0c;并启动这个流程。 创建Activiti工作流主要包含以下几步&#xff1a; 1、定义流程&#xff0c;按照BPMN的规范&#xff0c;使用流程定义工具&#xff0c;用流程符号把整个流程描述出来 2、部署…

Activiti 介绍

一、工作流 1.工作流 工作流(Workflow)&#xff0c;就是“业务过程的部分或整体在计算机应用环境下的自动化”&#xff0c;它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行&#xff0c;从而实现某个预期的业务目标&#xff0c;或…

Vuetify组件中常见的v-slot:activator=“{ on, attrs }“是什么意思?

在使用Vuetify组件时&#xff0c;常看到v-slot:activator"{ on, attrs }"以及插槽中的v-bind"attrs" v-on"on" 例如&#xff1a; 由于之前写代码时少有这种写法而且是第一次遇见&#xff0c;用久了难免想知道是什么意思。因为国内没有相关的问…

Tedddby Activator V5.1,免费绕过iOS 14.7Beta,支持iCloud登录

Tedddby Activator 是一款Windows下绕激活的工具&#xff0c;目前来说也是最好用的一款软件&#xff01; Tedddby Activator官网&#xff1a;https://tedddby.com 支持的功能 GSM两网绕过可以打电话/4G/短信/iCloud登陆/完美重启/消息推送 MEID三网游戏机绕过可以登陆iClou…

Spring Boot Actuator详解与深入应用(一):Actuator 1.x

《Spring Boot Actuator详解与深入应用》预计包括三篇&#xff0c;第一篇重点讲Spring Boot Actuator 1.x的应用与定制端点&#xff1b;第二篇将会对比Spring Boot Actuator 2.x 与1.x的区别&#xff0c;以及应用和定制2.x的端点&#xff1b;第三篇将会介绍Actuator metric指标…

springboot 集成 actuator

简介 spring-actuator做度量统计收集&#xff0c;使用Prometheus&#xff08;普罗米修斯&#xff09;进行数据收集&#xff0c;Grafana&#xff08;增强ui&#xff09;进行数据展示&#xff0c;用于监控生成环境机器的性能指标和业务数据指标。一般&#xff0c;我们叫这样的操作…

Activiti应用

1.介绍 Activiti是一个工作流引擎&#xff0c; activiti可以将业务系统中复杂的业务流程抽取出来&#xff0c;使用专门的建模语言 BPMN2.0进行定义&#xff0c;业务流程按照预先定义的流程进行执行&#xff0c;实现了系统的流程由activiti进行管理&#xff0c;减 少业务系统由…

springboot之Actuator

1、Actuator 介绍 Actuator是Springboot提供的用来对应用系统进行自省和监控的功能模块&#xff0c;借助于Actuator开发者可以很方便地对应用系统某些监控指标进行查看、统计等。 Actuator 的核心是端点 Endpoint&#xff0c;它用来监视应用程序及交互&#xff0c;spring-boo…

ActivitiListener

ActivitiListener 目录概述需求&#xff1a; 设计思路实现思路分析1.ActivitiListener2.Activity3.Gateway5.FieldExtension IOSpecification 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;sk…

SolidWorks2016软件,SW2010-2016.Activator.GUI.SSQ激活闪退解决办法:

SolidWorks2016软件&#xff0c;SW2010-2016.Activator.GUI.SSQ激活闪退解决办法&#xff1a; 解决方案&#xff1a; 原贴&#xff1a; https://xcshare.cn/other/1033.html

Actuator

1&#xff0c;简介 Actuator’ ktʃʊˌeɪtə是 Spring Boot 提供的对应用系统的自省和监控的 集成功能&#xff0c;可以对应用系统进行配置查看、相关功能统计等。在 Spring Cloud 中主要是完成 微服务的监控&#xff0c;完成监控治理。可以查看微服务间的数据处理和调用&…

Spring boot——Actuator 详解

一、什么是 Actuator Spring Boot Actuator 模块提供了生产级别的功能&#xff0c;比如健康检查&#xff0c;审计&#xff0c;指标收集&#xff0c;HTTP 跟踪等&#xff0c;帮助我们监控和管理Spring Boot 应用。 这个模块是一个采集应用内部信息暴露给外部的模块&#xff0c…

Spring Boot Actuator详解

Actuator简介 什么是Spring Boot Actuator&#xff1f; Spring Boot Actuator 模块提供了生产级别的功能&#xff0c;比如健康检查&#xff0c;审计&#xff0c;指标收集&#xff0c;HTTP跟踪等&#xff0c;帮助我们监控和管理Spring Boot应用。这个模块是一个采集应用内部信…

C# 反射之Activator用法举例

概述 程序运行时&#xff0c;通过反射可以得到其它程序集或者自己程序集代码的各种信息&#xff0c;包括类、函数、变量等来实例化它们&#xff0c;执行它们&#xff0c;操作它们&#xff0c;实际上就是获取程序在内存中的映像&#xff0c;然后基于这个映像进行各种操作。 Acti…