news 2026/4/16 13:46:10

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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操作对话框。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/11 23:22:30

华为MetaERP作为华为自主研发的企业资源规划系统,深度融合了实时智能技术,以提升企业运营效率和决策智能化水平

华为MetaERP作为华为自主研发的企业资源规划系统&#xff0c;深度融合了实时智能技术&#xff0c;以提升企业运营效率和决策智能化水平。其主要应用场景和方式包括&#xff1a;1. 实时数据处理与响应流式计算引擎&#xff1a;通过实时数据管道&#xff08;如Kafka、Flink等&…

作者头像 李华
网站建设 2026/4/13 12:00:58

KiCad V10新特性前瞻

https://forum.kicad.info/t/post-v9-new-features-and-development-news/58848 KiCad采用年度发布周期&#xff0c;主版本通常在每年2月至3月间发布。虽然正式版尚未推出&#xff0c;但由于KiCad始终秉持开源理念&#xff08;这恰是其最大优势&#xff09;&#xff0c;开发者…

作者头像 李华
网站建设 2026/4/12 16:48:37

我用 XinServer 解决了多端数据同步问题

我用 XinServer 解决了多端数据同步问题 最近在做一个外包项目&#xff0c;客户要求同时有微信小程序、管理后台&#xff0c;未来可能还要上App。需求一出来&#xff0c;我头就大了——这意味着一套数据&#xff0c;要服务至少三个不同的前端。按照传统做法&#xff0c;我得吭…

作者头像 李华
网站建设 2026/4/12 19:36:23

在IEEE-14总线系统中执行连续功率流 测试环境:MATLAB 读取IEEE14和 IEEE...

在IEEE-14总线系统中执行连续功率流 测试环境&#xff1a;MATLAB 读取IEEE14和 IEEE30系统数据。 连续潮流又称为延拓潮流&#xff0c;是电力系统电压稳定性分析的有力工具。 PV曲线由于反映了系统随着负荷的变化而引起的节点电压的变化状况&#xff0c;因此&#xff0c;已经被…

作者头像 李华