当前位置: 首页 > news >正文

CAD二次开发中关于非模态对话框的使用

1.添加 Dialog 资源(普通 DLL 中创建对话框,可视化操作)

普通 DLL 项目添加 Dialog 资源和 BRX 模板项目操作一致,全程可视化,无需手动写复杂脚本:

1.1 添加资源脚本文件(.rc)

  1. 右键项目名称 →「添加」→「新建项」;
  2. 左侧切换「Visual C++」→「资源」,右侧选择「资源脚本 (.rc)」;
  3. 文件名填写Resource.rc(默认即可),点击「添加」;
  4. VS 自动生成Resource.rc(资源脚本)和resource.h(资源 ID 管理),在「解决方案资源管理器」中可见。

1.2 新建 Dialog 资源(可视化创建)

  1. 双击「Resource.rc」,打开「资源视图」(若未显示:点击「视图」→「其他窗口」→「资源视图」);
  2. 在「资源视图」中,右键Resource.rc→「添加资源」;
  3. 弹出「添加资源」窗口,选择「Dialog」→ 点击「新建」;
  4. VS 自动创建默认对话框(ID:IDD_DIALOG1),并打开可视化对话框编辑器

1.3 修改 Dialog 属性(匹配立方体参数需求)

  1. 选中对话框(点击标题栏 / 空白区域,不选中内部按钮),按F4调出「属性窗口」;
  2. 逐一修改以下属性(确保后续代码能识别):
    • ID:删除默认IDD_DIALOG1,输入IDD_DIALOG_CUBE_PARAM(自定义唯一标识);
    • Caption:输入创建立方体参数(对话框标题,显示中文);
    • Font:下拉选择「Microsoft YaHei UI」,字号「9」(避免中文字体乱码);
    • Width:250(对话框宽度),Height:180(对话框高度)(属性窗口「布局」分类下);
    • Style:保持「Popup」+「Dialog Frame」(弹窗样式,默认即可);
  3. 点击「文件」→「保存」,暂不关闭对话框编辑器。

1.4 添加 Dialog 控件(编辑框 + 标签,实现参数输入)

  1. 调出「工具箱」(若未显示:Ctrl+Alt+X,或「视图」→「工具箱」);
  2. 添加 3 个「Static Text」(静态标签,说明文字):
    • 第 1 个标签:
      • 拖拽到对话框内,选中后按F4打开属性;
      • Caption长度:ID:保留IDC_STATIC(无需修改);
      • 布局位置:X=20Y=30(属性窗口「布局」分类下);
    • 第 2 个标签:
      • Caption宽度:,布局位置:X=20Y=70
    • 第 3 个标签:
      • Caption高度:,布局位置:X=20Y=110
  3. 添加 3 个「Edit Control」(编辑框,输入长宽高):
    • 第 1 个编辑框(对应长度):
      • 拖拽到对话框内,选中后按F4打开属性;
      • IDIDC_EDIT_LENGTH(自定义唯一 ID,后续代码调用);
      • 勾选「Auto HScroll」(自动横向滚动,优化输入体验);
      • 布局位置:X=70Y=30,尺寸:Width=150Height=20
    • 第 2 个编辑框(对应宽度):
      • IDIDC_EDIT_WIDTH,布局位置:X=70Y=70,尺寸同前;
    • 第 3 个编辑框(对应高度):
      • IDIDC_EDIT_HEIGHT,布局位置:X=70Y=110,尺寸同前;
  4. 保留默认「确定」「取消」按钮(BricsCAD 识别默认 IDIDOK/IDCANCEL):
    • 「确定」按钮:位置X=60Y=145,尺寸60×25
    • 「取消」按钮:位置X=130Y=145,尺寸60×25
  5. 调整完成后,点击「文件」→「保存全部」,VS 自动更新Resource.rcresource.h

1.5 验证资源 ID(确保resource.h自动生成)

双击打开resource.h,确认以下 ID 已自动添加(VS 自动生成,无需手动编写,数值可不同,名称一致即可):

#ifndef RESOURCE_H #define RESOURCE_H #define IDD_DIALOG_CUBE_PARAM 101 #define IDC_EDIT_LENGTH 1001 #define IDC_EDIT_WIDTH 1002 #define IDC_EDIT_HEIGHT 1003 #define IDC_STATIC -1 #endif // RESOURCE_H

2. 一段代码示例

#include "StdAfx.h" #include "Box.h" #include "resource.h" #include <windows.h> #include <tchar.h> // 全局变量:保存插件自身模块句柄(用于获取对话框资源) static HMODULE g_hPluginModule = NULL; // 全局结构体:存储立方体参数 typedef struct { double dLength; // 长度 double dWidth; // 宽度 double dHeight; // 高度 BOOL bDialogActive; // 对话框是否激活 HWND hDialog; // 对话框句柄 } CubeParamStruct; // 全局变量:初始化默认参数(100×100×100) static CubeParamStruct g_CubeParam = { 100.0, 100.0, 100.0, FALSE, NULL }; // 对话框过程函数(非模态) INT_PTR CALLBACK CubeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) //对话框句柄、消息类型、消息的附加细节(如控件ID和通知码) { switch (uMsg) //判断消息类型 { // 对话框初始化 case WM_INITDIALOG: { g_CubeParam.hDialog = hDlg; g_CubeParam.bDialogActive = TRUE; // 初始化编辑框显示默认值 TCHAR szValue[64]; _stprintf_s(szValue, _T("%.2f"), g_CubeParam.dLength); SetDlgItemText(hDlg, IDC_EDIT_LENGTH, szValue); _stprintf_s(szValue, _T("%.2f"), g_CubeParam.dWidth); SetDlgItemText(hDlg, IDC_EDIT_WIDTH, szValue); _stprintf_s(szValue, _T("%.2f"), g_CubeParam.dHeight); SetDlgItemText(hDlg, IDC_EDIT_HEIGHT, szValue); return TRUE; } // 按钮点击消息处理 case WM_COMMAND: { switch (LOWORD(wParam)) { // 确定按钮(创建立方体) case IDOK: { TCHAR szBuffer[64]; // 读取编辑框参数 GetDlgItemText(hDlg, IDC_EDIT_LENGTH, szBuffer, 64); g_CubeParam.dLength = _tstof(szBuffer); GetDlgItemText(hDlg, IDC_EDIT_WIDTH, szBuffer, 64); g_CubeParam.dWidth = _tstof(szBuffer); GetDlgItemText(hDlg, IDC_EDIT_HEIGHT, szBuffer, 64); g_CubeParam.dHeight = _tstof(szBuffer); // 合法性校验 if (g_CubeParam.dLength <= 0.001 || g_CubeParam.dWidth <= 0.001 || g_CubeParam.dHeight <= 0.001) { MessageBox(hDlg, _T("长宽高必须大于0.001!"), _T("错误"), MB_OK | MB_ICONERROR); return TRUE; } // 创建立方体 try { Box::createBoxSolid( g_CubeParam.dLength, g_CubeParam.dWidth, g_CubeParam.dHeight, AcGeVector3d(100, 100, 100), 1 // 红色 ); acutPrintf(_T("\n* 立方体创建成功!尺寸:%.2f×%.2f×%.2f"), g_CubeParam.dLength, g_CubeParam.dWidth, g_CubeParam.dHeight); } catch (...) { MessageBox(hDlg, _T("创建立方体失败!"), _T("错误"), MB_OK | MB_ICONERROR); } return TRUE; } // 取消按钮(关闭对话框) case IDCANCEL: { DestroyWindow(hDlg); g_CubeParam.bDialogActive = FALSE; g_CubeParam.hDialog = NULL; return TRUE; } } break; } // 对话框关闭消息 case WM_CLOSE: DestroyWindow(hDlg); g_CubeParam.bDialogActive = FALSE; g_CubeParam.hDialog = NULL; return TRUE; case WM_DESTROY: g_CubeParam.bDialogActive = FALSE; g_CubeParam.hDialog = NULL; return TRUE; } return FALSE; } // 插件核心类:继承 AcRxArxApp 基类(BRX 模板规范) class CubePlugin : public AcRxArxApp { public: // 构造函数:调用父类构造,初始化插件基础信息 CubePlugin() : AcRxArxApp() {} // 服务器组件注册:空实现(满足 BRX 框架要求,无复杂组件需注册) virtual void RegisterServerComponents() { } // 插件加载时触发:初始化配置 + 打印提示信息 virtual AcRx::AppRetCode On_kInitAppMsg(void* pAppData) { // 调用父类默认初始化,完成底层绑定 AcRx::AppRetCode result = AcRxArxApp::On_kInitAppMsg(pAppData); // 配置插件支持多文档 + 允许运行时卸载 acrxRegisterAppMDIAware(pAppData); acrxUnlockApplication(pAppData); // 打印加载成功提示 acutPrintf(_T("\n* 立方体 DLL 插件加载成功!")); acutPrintf(_T("\n* 可用命令:BCreateCube、CubeDlg")); return result; } // 插件卸载时触发:清理命令 + 关闭对话框 virtual AcRx::AppRetCode On_kUnloadAppMsg(void* pAppData) { // 清理已打开的对话框 if (g_CubeParam.bDialogActive && g_CubeParam.hDialog && IsWindow(g_CubeParam.hDialog)) { DestroyWindow(g_CubeParam.hDialog); } g_CubeParam.bDialogActive = FALSE; g_CubeParam.hDialog = NULL; // 调用父类默认卸载逻辑 return AcRxArxApp::On_kUnloadAppMsg(pAppData); } // 其他生命周期方法:空实现(保证类的完整性,满足 BRX 框架要求) virtual AcRx::AppRetCode On_kLoadDwgMsg(void* pAppData) { return AcRxArxApp::On_kLoadDwgMsg(pAppData); } virtual AcRx::AppRetCode On_kUnloadDwgMsg(void* pAppData) { return AcRxArxApp::On_kUnloadDwgMsg(pAppData); } // BRX 命令1:快速创建默认立方体(静态成员函数,符合 BRX 命令规范) static void CubePluginBCreateCube(void) { Box::createBoxSolid(100.0, 100.0, 100.0, AcGeVector3d(100, 100, 100), 1); acutPrintf(_T("\n* 默认立方体创建成功!(尺寸:100×100×100)")); } // BRX 命令2:打开参数对话框(静态成员函数,符合 BRX 命令规范) static void CubePluginCubeDlg(void) { // 若对话框已打开,直接激活 if (g_CubeParam.hDialog && IsWindow(g_CubeParam.hDialog) && g_CubeParam.bDialogActive) { SetForegroundWindow(g_CubeParam.hDialog); ShowWindow(g_CubeParam.hDialog, SW_SHOW); return; } // 获取BricsCAD主窗口句柄(兜底使用桌面窗口) HWND hWndAcad = adsw_acadMainWnd(); if (hWndAcad == NULL) { hWndAcad = GetDesktopWindow(); } // 创建非模态对话框 HWND hDlg = CreateDialogParam( g_hPluginModule, MAKEINTRESOURCE(IDD_DIALOG_CUBE_PARAM), hWndAcad, CubeDlgProc, 0 ); if (hDlg == NULL) { acutPrintf(_T("\n* 错误:无法创建对话框!错误代码:%d"), GetLastError()); return; } // 显示对话框 ShowWindow(hDlg, SW_SHOW); UpdateWindow(hDlg); // 更新全局变量 g_CubeParam.hDialog = hDlg; g_CubeParam.bDialogActive = TRUE; } }; // 关键入口宏:告诉 BRX 框架核心插件类(无法省略) IMPLEMENT_ARX_ENTRYPOINT(CubePlugin) // DLL 入口函数:保存插件模块句柄 BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // 插件加载时,保存自身模块句柄 g_hPluginModule = hModule; break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // 命令1:自动注册 BCreateCube(遵循 BRX 模板自动注册宏规范) ACED_ARXCOMMAND_ENTRY_AUTO(CubePlugin, CubePlugin, BCreateCube, BCreateCube, ACRX_CMD_TRANSPARENT, NULL) // 命令2:自动注册 CubeDlg(遵循 BRX 模板自动注册宏规范) ACED_ARXCOMMAND_ENTRY_AUTO(CubePlugin, CubePlugin, CubeDlg, CubeDlg, ACRX_CMD_TRANSPARENT, NULL)

3. 对代码进行解释

3.1 关于对话框消息处理函数(回调函数)

Windows 系统会在对话框有事件发生(比如点击按钮、关闭窗口)时,自动调用这个函数,并把相关信息通过这四个参数传递给你,让你决定如何处理这些事件。

逐个拆解参数含义

函数原型:

INT_PTR CALLBACK CubeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)

1.HWND hDlg

  • 类型HWND= Handle to Window(窗口句柄),是 Windows 给每个窗口 / 对话框分配的唯一 “身份证号”。
  • 含义:这个参数指向当前触发消息的对话框窗口本身。
  • 实际用途:你可以通过这个句柄操作对话框,比如:
    • 给对话框里的编辑框设置内容(SetDlgItemText(hDlg, IDC_EDIT1, "内容"));
    • 关闭这个对话框(EndDialog(hDlg, IDOK));
    • 获取对话框中控件的句柄(GetDlgItem(hDlg, IDC_BUTTON1))。
  • 通俗类比:相当于你收到了一封信,hDlg就是信封上写的 “收件人地址”,告诉你这是给哪个对话框的消息。

2.UINT uMsg

  • 类型UINT= Unsigned Integer(无符号整数),本质是 Windows 定义的消息常量。
  • 含义:这个参数是消息类型,告诉函数 “发生了什么事”。Windows 预定义了大量消息常量,每个常量对应一个具体事件。
  • 常见取值示例
    消息常量含义
    WM_INITDIALOG对话框刚创建、初始化时触发
    WM_COMMAND用户点击了按钮 / 菜单等控件
    WM_CLOSE用户点击了对话框的关闭按钮
    WM_DESTROY对话框即将被销毁时触发
  • 实际用途:你会在函数里用switch(uMsg)分支判断消息类型,然后针对性处理。
  • 通俗类比:相当于信封里的 “事件说明”,比如 “有人按了确认按钮”“要关闭窗口了”。

3.WPARAM wParam

  • 类型WPARAM= Window Parameter(窗口参数),本质是一个 32/64 位的整数(根据系统位数)。
  • 含义消息的附加参数 1,具体值取决于uMsg的类型 —— 不同的消息,wParam承载的信息不同。
  • 常见示例
    • uMsg = WM_COMMAND时,wParam的低 16 位是控件 ID(比如点击的按钮 IDIDC_BUTTON_OK),高 16 位是通知码(比如BN_CLICKED表示按钮被点击);
    • uMsg = WM_KEYDOWN时,wParam是按下的键盘按键码(比如VK_ENTER表示回车键);
  • 通俗类比:相当于事件说明的 “补充细节 1”,比如 “按了确认按钮” 这个事件里,wParam告诉你 “是 ID 为 1001 的那个确认按钮”。

4.LPARAM lParam

  • 类型LPARAM= Long Parameter(长参数),也是 32/64 位整数,和WPARAM是一对 “搭档参数”。
  • 含义消息的附加参数 2,同样取决于uMsg的类型,通常承载更复杂的信息(比如指针、坐标、控件句柄等)。
  • 常见示例
    • uMsg = WM_COMMAND时,lParam是触发事件的控件句柄(比如被点击按钮的句柄);
    • uMsg = WM_MOUSEMOVE时,lParam的低 16 位是鼠标 X 坐标,高 16 位是 Y 坐标;
    • uMsg = WM_INITDIALOG时,lParam可能携带创建对话框时传递的自定义数据;
  • 通俗类比:相当于事件说明的 “补充细节 2”,比如 “按了确认按钮” 这个事件里,lParam告诉你 “这个按钮的具体句柄是多少”。

补充:函数返回值和修饰符

为了让你理解更完整,额外说明函数头部的其他标识:

  • INT_PTR:函数返回值类型,通常返回TRUE/FALSE或特定值(比如处理了消息返回TRUE,未处理返回FALSE,让系统默认处理);
  • CALLBACK:是 Windows 定义的宏,本质是__stdcall,指定函数的调用约定(参数传递、栈清理的规则),确保系统能正确调用这个回调函数。

实战示例(帮你理解参数配合使用)

下面是一个简化的CubeDlgProc实现,直观展示参数如何配合:

INT_PTR CALLBACK CubeDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: // 对话框初始化 // 用hDlg(对话框句柄)给编辑框设置初始内容 SetDlgItemText(hDlg, IDC_EDIT1, "请输入内容"); return TRUE; // 表示处理了这个消息 case WM_COMMAND: // 控件事件 // wParam低16位是控件ID,HIWORD/LOWORD是提取高低位的宏 int nCtrlID = LOWORD(wParam); int nNotifyCode = HIWORD(wParam); HWND hCtrl = (HWND)lParam; // lParam是控件句柄 if (nCtrlID == IDC_BUTTON_OK && nNotifyCode == BN_CLICKED) { // 点击了“确认”按钮,用hDlg操作对话框 MessageBox(hDlg, "你点击了确认按钮", "提示", MB_OK); EndDialog(hDlg, IDOK); // 关闭对话框 return TRUE; } break; case WM_CLOSE: // 关闭对话框 EndDialog(hDlg, IDCANCEL); return TRUE; } // 未处理的消息,交给系统默认处理 return FALSE; }

总结

  1. hDlg:当前对话框的 “身份证”(句柄),用于操作对话框本身;
  2. uMsg:核心消息类型,告诉函数 “发生了什么事”(初始化、点击按钮、关闭等);
  3. wParam/lParam:消息的附加细节,不同消息对应不同含义,是处理具体事件的关键;
  4. 四个参数由 Windows 系统自动传递,你只需在函数里根据uMsg判断类型,结合wParam/lParam处理逻辑,再通过hDlg操作对话框。
http://www.jsqmd.com/news/299147/

相关文章:

  • 机器学习——线性回归、代价(损失)函数、L1L2正则化、梯度下降算法、正态分布和标准正态分布
  • 微积分:世界是用“微分”写成的,我们是用“积分”读懂的
  • 宝塔面板一键部署 Emlog 教程:从服务器准备到站点上线全攻略
  • 爬虫项目:利用 Playwright 和 Asyncio 高效收集酒店信息
  • 华为MetaERP锂电池行业数字化转型总体蓝图架构设计解决方案
  • 将“100小时精通Oracle ERP,华为MetaERP和SAP”称为“不得不把握的世纪机会”
  • 华为MetaERP作为华为自主研发的新一代企业资源计划系统,其成功部署和高效运行依赖于多个核心技术组件和生态合作伙伴的协同支持
  • 232. 用栈实现队列
  • 吐血推荐8个AI论文工具,本科生搞定毕业论文!
  • SAP ERP的成本中心与Oracle ERP会计科目弹性域中部门段的比较
  • 在SAP系统中,利润中心(Profit Center)和成本中心(Cost Center)是两个关键的组织单元,用于企业内部管理和财务控制
  • 在SAP ERP中,控制范围(Controlling Area)是管理会计(CO模块)的核心组织单元,用于成本核算、成本中心会计、利润中心会计等
  • 华为MetaERP作为华为自主研发的企业资源规划系统,深度融合了实时智能技术,以提升企业运营效率和决策智能化水平
  • 8.开发工具
  • X光检测技术如何保障生产线上的产品安全与质量
  • 主流门店管理软件如何选?客观对比为商家提供参考
  • gops 工具在 Cilium 中的应用指南
  • 刘洋洋《爱在照亮》温暖上线 解锁平凡日常里的爱的模样
  • qt之QTableView设置模型代理代码示例
  • 【数据集】【YOLO】【目标检测】口罩材料集,口罩佩戴识别材料集 1971 张,YOLO佩戴口罩检测算法实战训练教程。
  • intel白皮书卷2 第二章(AI翻译)
  • intel白皮书卷2 附录A(AI翻译)
  • https 证书 生成安装笔记
  • 半导体企业数字化转型技术方案:SAP S/4HANA 私有云如何打通研产供销财全链路?
  • SAP ERP 公有云 AI / 机器学习落地指南:技术架构、业务场景与实施路径
  • 一篇文章讲清楚:中转API如何用Python调用ChatGPT
  • 智能井盖安全监测系统的设计与实现
  • 深度测评9个论文写作工具,自考学生一键生成论文工具推荐!
  • 【节点】[NormalVector节点]原理解析与实际应用
  • 我在运动-轨迹查看器