ARX wxwidgets 界面开发
本帖最后由 橡皮 于 2025-8-22 16:00 编辑1. wxwidgets 库文件下载(当然可以自己下载源码编译)
下载链接:Downloads - wxWidgets
oneDrive:wxWidgets
官方使用配置说明:How to use wxMSW binaries | wxWidgets
下载后解压并将文件夹下内容直接拷贝到一块
2. 创建 ARX 项目,配置 wxwidgets 环境
推荐ARX项目模版一键创建项目直接创建,当然如果愿意可后边将 wxwidgets 配置写到这个模板里边 ,
这里不再演示创建过程,创建之后,添加上一步 wxwidgets 库文件夹中的属性文件 wxwidgets.props
3. 添加 wxwidgets 主窗口,重写初始化函数
在 arxEntryPoint.cpp 文件中添加如下函数
class TRApp : public wxApp {
public:
virtual bool OnInit() override
{
return true;
}
};
IMPLEMENT_APP_NO_MAIN(TRApp);
static bool wxStarted = false;
void EnsureWxWidgetsInitialized() {
if (!wxStarted) {
int argc = 0;
char** argv = nullptr;
wxStarted = true;
wxEntryStart(argc, argv);
wxTheApp->CallOnInit();
}
}
void CleanupWxWidgets() {
if (wxStarted) {
wxTheApp->OnExit();
wxEntryCleanup();
wxStarted = false;
}
}并在 ARX 初始化函数中调用(也就是同步初始化创建 wxwidgets 主窗口)
virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {
AcRx::AppRetCode retCode =AcRxArxApp::On_kInitAppMsg (pkt) ;
EnsureWxWidgetsInitialized();
return (retCode) ;
}卸载时同步释放资源
virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt) {
CleanupWxWidgets();
AcRx::AppRetCode retCode =AcRxArxApp::On_kUnloadAppMsg (pkt) ;
return (retCode) ;
}
4. wxwidgets 实例
经过前三步就可以直接使用 wxwidgets 创建 UI 界面了(可以代码创建也可以使用xrc资源文件,这里只展示代码创建的)
a. 直接用 AI 生成了一个简单地如下
#include <wx/wx.h>
// 自定义对话框类
class MyDialog : public wxDialog
{
public:
// 构造函数
MyDialog(wxWindow* parent, const wxString& title)
: wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxSize(300, 200))
{
// 创建垂直布局管理器
wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL);
// 添加静态文本
wxStaticText* text = new wxStaticText(this, wxID_ANY,
"这是一个简单的 wxWidgets 对话框!\n\n"
"欢迎使用 wxWidgets 库。",
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
// 设置文本字体
wxFont font(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
text->SetFont(font);
// 添加文本到布局,设置边距
vbox->Add(text, 1, wxALL | wxEXPAND, 20);
// 创建水平布局放置按钮
wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
// 添加确定按钮
wxButton* okBtn = new wxButton(this, wxID_OK, "确定", wxDefaultPosition, wxSize(70, 30));
hbox->Add(okBtn, 0, wxRIGHT, 10);
// 添加取消按钮
wxButton* cancelBtn = new wxButton(this, wxID_CANCEL, "取消", wxDefaultPosition, wxSize(70, 30));
hbox->Add(cancelBtn);
// 将水平布局添加到垂直布局
vbox->Add(hbox, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, 10);
// 设置对话框的布局
SetSizer(vbox);
// 居中显示对话框
Centre();
}
};
b. 自己也简单做了一个
#pragma once
#include <wx/wx.h>
class MyDialog : public wxDialog {
public:
MyDialog(wxWindow* parent);
private:
void OnClose(wxCloseEvent& event);
void OnOK(wxCommandEvent& event);
void OnCancel(wxCommandEvent& event);
void OnCharHook(wxKeyEvent& event);
};
// cpp 文件内容
#include "StdAfx.h"
#include "MyDialog.h"
class CDocLocker
{
public:
CDocLocker() { acDocManager->lockDocument(acDocManager->curDocument()); }
~CDocLocker() { acDocManager->unlockDocument(acDocManager->curDocument()); }
};
MyDialog::MyDialog(wxWindow* parent)
: wxDialog(parent, wxID_ANY, "My Custom Dialog", wxDefaultPosition, wxSize(400, 200),
wxDEFAULT_DIALOG_STYLE | wxCLOSE_BOX | wxSTAY_ON_TOP)
{
// 控件布局
auto* mainSizer = new wxBoxSizer(wxVERTICAL);
mainSizer->Add(new wxStaticText(this, wxID_ANY, "Welcome to use custom dialog"), 0, wxALL | wxALIGN_CENTER, 15);
auto* bSizer1 = new wxBoxSizer(wxHORIZONTAL);
auto* m_Cancel = new wxButton(this, wxID_CANCEL, wxT("取消"), wxDefaultPosition, wxDefaultSize, 0);
bSizer1->Add(m_Cancel, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5);
auto* m_Ok = new wxButton(this, wxID_OK, wxT("确定"), wxDefaultPosition, wxDefaultSize, 0);
bSizer1->Add(m_Ok, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5);
mainSizer->Add(bSizer1, 0, wxEXPAND | wxALL, 5);
SetSizerAndFit(mainSizer);
// 事件绑定
m_Ok->Bind(wxEVT_BUTTON, &MyDialog::OnOK, this);
m_Cancel->Bind(wxEVT_BUTTON, &MyDialog::OnCancel, this);
Bind(wxEVT_CHAR_HOOK, &MyDialog::OnCharHook, this);
Bind(wxEVT_CLOSE_WINDOW, &MyDialog::OnClose, this);
}
void MyDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) {
Show(false); // 或 EndModal(wxID_CANCEL); // 模态对话框
}
void MyDialog::OnOK(wxCommandEvent& WXUNUSED(event)) {
Show(false);
acedGetAcadDwgView()->SetFocus();
CDocLocker docLocker;
ads_name ent;
ads_point pt;
if (acedEntSel(L"\nPick Curve: ", ent, pt) == RTNORM) {
AcDbObjectId objId;
AcDbEntity* pEnt = nullptr;
if (Acad::eOk == acdbGetObjectId(objId, ent)
&& Acad::eOk == acdbOpenObject(pEnt, objId, AcDb::kForWrite))
{
pEnt->setColorIndex(pEnt->colorIndex() > 254 ? 1 : pEnt->colorIndex() + 1);
pEnt->close();
}
}
else {
acutPrintf(L"\nselect no curve.");
}
}
void MyDialog::OnClose(wxCloseEvent& WXUNUSED(event)) {
Show(false); // 或 EndModal(wxID_CANCEL); // 模态对话框
}
void MyDialog::OnCharHook(wxKeyEvent& event) {
if (event.GetKeyCode() == WXK_ESCAPE) {
Show(false); // 或 EndModal(wxID_CANCEL); // 模态对话框
return;
}
event.Skip();
}
使用过程和 ARX 中 MFC 使用方式一致
MyDialog* dlg = nullptr;
static void MyGroupTT1 () {
if (!dlg)
{
dlg = new MyDialog(nullptr);
}
dlg->Show();
}
static void MyGroupTT2() {
MyDialog2 dlg(nullptr, L"second dialog");
dlg.ShowModal();
}
ACED_ARXCOMMAND_ENTRY_AUTO(CwxWidgetsDemoApp, MyGroup, TT1, TT1, ACRX_CMD_MODAL, NULL)
ACED_ARXCOMMAND_ENTRY_AUTO(CwxWidgetsDemoApp, MyGroup, TT2, TT2, ACRX_CMD_MODAL, NULL
5. 演示
因为使用的是动态链接库所以加载插件前一定要将库所在文件夹添加到 CAD 的搜索路径里
演示如下:
下边是之前的帖子一维下料使用wxwidgets实现(采用的 XRC 资源文件,他是模块化的可以重复组合使用)
这个是直接将上边的代码添加到 ARX 项目中,并添加了绘制图形函数之后的插件演示
资源推荐:
wxwidgets 创建 UI 界面软件可以采用 wxFormBuilder 或者 DialogBlocks(推荐)
Microsoft Visual C++ compiler versions 14.0, 14.1, 14.2 and 14.3 (corresponding to marketing product names of Microsoft Visual Studio 2015, 2017, 2019 and 2022 respectively).
Please note that MSVC 14.x versions are ABI-compatible and the same set of binaries is used for all of them.
本帖最后由 lovewanting002 于 2025-10-9 14:53 编辑
这几天在弄arx和wxwidgets ,有几个注意点
一、wxwidgets不要使用debug版本的库,直接使用release版本的库.arx的C++的代码生成无论是debug还是release默认都是/MD
二、可以使用wxformbuilder进界面绘制的时候,主要使用wxboxsizer的布局,可以通过proportion的值控制比例大小占用,wxEXPAND控制剩余占满。吾爱破解有一个中文版的,v3.90
三、目前只有3.2.8还支持低版本的C++,更高级的版本已经拥护C++11了。
附带Release的静态库名称(3.2.8)已通过vs2008进行验证
wxbase32u.lib
wxbase32u_net.lib
wxbase32u_xml.lib
wxexpat.lib
wxjpeg.lib
wxmsw32u_adv.lib
wxmsw32u_aui.lib
wxmsw32u_core.lib
wxmsw32u_gl.lib
wxmsw32u_html.lib
wxmsw32u_media.lib
wxmsw32u_propgrid.lib
wxmsw32u_qa.lib
wxmsw32u_ribbon.lib
wxmsw32u_richtext.lib
wxmsw32u_stc.lib
wxmsw32u_webview.lib
wxmsw32u_xrc.lib
wxpng.lib
wxregexu.lib
wxscintilla.lib
wxtiff.lib
wxzlib.lib
思路基本理清了,
HWND acadHwnd = adsw_acadMainWnd();
wxNativeContainerWindow parent((WXHWND)acadHwnd);
CArxWxDialog theDialog(&parent);
parent.Enable(false);//禁用父窗口
theDialog.ShowModal();
parent.Enable(true);//避免忘记启用
在关闭按钮的事件中,提前解锁,这样对话框退出的时候,才能把焦点给cad,否则在解开禁用时就会出现cad不在前面的问题。
void CArxWxDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) {
wxWindow*pParent=GetParent();
if (pParent)
{
pParent->Enable(true); //对话框结束前解开禁用
}
EndModal(wxID_CANCEL);
//Show(false); // 或 EndModal(wxID_CANCEL); // 模态对话框
}
大致是这个思路,封装封装,应该可以作为基类使用了。
try it 如果wxwindow不设置父窗口,那么他和cad就没有关系,他们是两个窗口,而showmodal只是消息阻塞,cad还能点击,如果点击就会挡住wxwindow。
模态窗口的创建大概是这么个流程,构建对象,设置父窗口,弹窗窗口,窗口的焦点自然从父窗口到了子窗口,系统创建模态窗口的时候会禁用父窗口,关闭的时候启用父窗口,焦点自然就回到了父窗口。
而wxwindow如果不能设置正确的设置父窗口,那么他是当做一个独立的窗口运行,关闭时焦点不会切换会父窗口,手动设置焦点就会闪屏。
手动模态对话框
CWnd* mfcWnd = acedGetAcadFrame();
mfcWnd->EnableWindow(FALSE);
CArxWxDialog dlg(nullptr);
dlg.ShowModal();
mfcWnd->EnableWindow(TRUE);
mfcWnd->SetFocus();
wxwidgets 是跨平台的 我看官方3.3低版本vc已经没有支持了,
如果不需要编译低版本ObjectARX,还是可以使用.
个人观点,如果是开发ObjecARX,没有跨平台需求感觉意义不是很大.
ps:另外我试了下,也可能是我技术不行,模态对话框有点别扭.好像设置父窗口不太行,.感觉还没duilib容易融合.
我是下载过程中就断,一直下载不了。看看这个ui gzxl 发表于 2025-8-22 14:18
我是下载过程中就断,一直下载不了。看看这个ui
稍等我搞个自己的云盘链接 edata 发表于 2025-8-22 12:36
我看官方3.3低版本vc已经没有支持了,
如果不需要编译低版本ObjectARX,还是可以使用.
个人观点,如果是开发 ...
设置父窗口不太行是个什么情况啊 gzxl 发表于 2025-8-22 14:18
我是下载过程中就断,一直下载不了。看看这个ui
https://4brubberi-my.sharepoint.com/:f:/g/personal/tao_4brubberi_onmicrosoft_com/EhqlSC_PPXhLmfs5peo0M0kBWTb1ogk0o-oC7RyCrDrcIQ?e=vBW1R1 本帖最后由 橡皮 于 2025-8-22 15:49 编辑
原来代码在插件卸载时没有写 wxwidgets 主窗口处理,会导致卸载的时候程序崩溃。。。。忘了这个了
下边是卸载前要做的
void CleanupWxWidgets() {
if (wxStarted) {
wxTheApp->OnExit();
wxEntryCleanup();
wxStarted = false;
}
}
virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt) {
CleanupWxWidgets();
AcRx::AppRetCode retCode =AcRxArxApp::On_kUnloadAppMsg (pkt) ;
return (retCode) ;
}
SetParent设置cad窗口无效,模态窗口不能禁用父窗口,手动禁用和解禁等会闪屏。