如何将HDevEngine窗口嵌入wxWidgets面板?
将HDevEngine窗口嵌入wxWidgets面板的调整方案
HDevEngine作为C++环境下的脚本解释器,默认会弹出独立窗口显示运行结果,要把它嵌入wxWidgets现有面板,得从几个关键地方调整现有代码:
核心修改点
- 修正变量名笔误:代码里的
hDevProgram是拼写错误,应该替换成my_program,否则会触发编译错误。 - 延长实例生命周期:当前
my_engine和my_program是构造函数里的局部变量,构造完成后就会销毁,必须改成类的成员变量,否则程序执行时会出现资源释放问题。 - 绑定窗口尺寸同步:wxWidgets面板的初始尺寸可能还没完全确定,要绑定
wxEVT_SIZE事件,在面板尺寸变化时同步调整HALCON窗口的大小,避免显示错位。 - 自定义OperatorImpl控制窗口创建:默认HDevEngine会自动新建窗口,得在
MyHDevOperatorImpl里重写OpenWindow方法,强制使用我们预先绑定到wxPanel的窗口,禁止新建独立窗口。 - 异步执行避免UI阻塞:直接在构造函数里执行
Execute()会卡死wxWidgets界面,要把HDev程序的执行放到单独线程里。
修改后的完整代码
#include <wx/wx.h> #include "HalconCpp.h" #include "HDevEngineCpp.h" #include "HDevThread.h" #include "my_error_output.h" #include "my_hdevoperatorimpl.h" using namespace HalconCpp; using namespace HDevEngine; class MyFrame : public wxFrame { private: HDevEngine m_engine; HDevProgram m_program; Htuple m_windowID; wxPanel* m_panel1; // 用于异步执行HDev程序的线程类 class HDevExecutionThread : public wxThread { private: HDevProgram m_program; Htuple m_windowID; public: HDevExecutionThread(const HDevProgram& program, const Htuple& windowID) : wxThread(wxTHREAD_JOINABLE), m_program(program), m_windowID(windowID) {} virtual ExitCode Run() override { // 指定当前线程使用的绘图窗口 HDevWindowStack::Push(m_windowID); try { HDevProgramCall program_call(m_program); program_call.Execute(); } catch (HDevEngineException& e) { // 捕获并显示执行错误 wxMessageBox(wxString(e.GetErrorMessage().CStr()), "执行错误", wxOK | wxICON_ERROR); } HDevWindowStack::Pop(); return nullptr; } }; public: MyFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(800, 600)) { // 创建布局结构 wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); m_panel1 = new wxPanel(this, wxID_ANY); wxPanel* panel2 = new wxPanel(this, wxID_ANY); sizer->Add(m_panel1, 1, wxEXPAND | wxALL, 5); sizer->Add(panel2, 1, wxEXPAND | wxALL, 5); SetSizer(sizer); // 初始化HDevEngine,绑定自定义Operator实现 MyHDevOperatorImpl op_impl; m_engine.SetHDevOperatorImpl(&op_impl); // 加载目标HDev程序 std::string program_path = Data::get().getAppData().PathHdev; m_program.LoadProgram(program_path.c_str()); // 绑定尺寸变化事件,同步调整HALCON窗口 Bind(wxEVT_SIZE, &MyFrame::OnSize, this); // 初始化HALCON窗口 CreateHalconWindow(); // 启动异步线程执行HDev程序 HDevExecutionThread* thread = new HDevExecutionThread(m_program, m_windowID); if (thread->Run() != wxTHREAD_NO_ERROR) { wxMessageBox("无法启动执行线程", "错误", wxOK | wxICON_ERROR); delete thread; } } ~MyFrame() { // 销毁时关闭HALCON窗口 if (HDevWindowStack::IsOpen()) { CloseWindow(HDevWindowStack::Pop()); } } private: void CreateHalconWindow() { // 先关闭已存在的窗口 if (HDevWindowStack::IsOpen()) { CloseWindow(HDevWindowStack::Pop()); } // 获取面板的客户区尺寸创建窗口 wxSize size = m_panel1->GetClientSize(); OpenWindow(0, 0, size.GetWidth(), size.GetHeight(), (Hlong)m_panel1->GetHandle(), "visible", "", &m_windowID); HDevWindowStack::Push(m_windowID); } void OnSize(wxSizeEvent& event) { // 延迟执行窗口调整,确保面板尺寸已更新 wxCallAfter([this]() { CreateHalconWindow(); }); event.Skip(); } }; class MyApp : public wxApp { public: virtual bool OnInit() override { MyFrame *frame = new MyFrame("wxWidgets嵌入HDevEngine示例"); frame->Show(true); return true; } }; wxIMPLEMENT_APP(MyApp);
自定义OperatorImpl的关键修改
要彻底阻止HDevEngine新建独立窗口,必须在MyHDevOperatorImpl中重写OpenWindow方法,确保所有绘图都在指定的wxPanel窗口内进行:
class MyHDevOperatorImpl : public HDevOperatorImpl { public: virtual void OpenWindow(const Htuple& Row, const Htuple& Column, const Htuple& Width, const Htuple& Height, const Htuple& ParentWindowHandle, const Htuple& Mode, const Htuple& Machine, Htuple* WindowHandle) override { // 直接基于传入的父窗口句柄(wxPanel的句柄)创建窗口 HalconCpp::OpenWindow(Row, Column, Width, Height, ParentWindowHandle, Mode, Machine, WindowHandle); // 禁止自动创建独立窗口,强制复用指定的父容器 } };
内容的提问来源于stack exchange,提问作者juanlg
相关产品推荐
相关产品推荐

