wxWidgets项目的最佳开发流程

这种自动编译xrc文件、派生窗体类的机制将变化控制在wxFormBuilder界面设计上,一定程度上缓解了工具自动生成代码和手动调整代码两者之间的矛盾,从而保证了开发流程的连贯性。

近期,对wxWidgets框架进行了断断续续的摸索,基本确定将它作为今后开发个人桌面小工具的首选技术,并打算对其设计逻辑和源代码进行适当探索。

上一篇关于wxWidgets的文章介绍了如何安装编译源代码、引入props配置文件,从而创建一个可运行的wxWidgets项目。但在实际项目开发过程中,开发环境配置只是第一步,要保证开发效率,还需要一整套流程来应对前端界面和后端业务交互迭代的情况。

推荐使用wxFormBuilder进行wxWidgets项目的前端界面设计,具体的使用方式有多种:①直接使用该工具生成的C+ +代码;②直接使用该工具生成的XRC资源文件;③使用XRC资源文件编译得到的C+ +代码。

以上第②种方式生成的程序在运行时必须附带XRC资源文件,而采用第①、③种方式时,资源文件可以嵌入程序,发行更方便。另外,使用wxFormBuilder生成代码时,最好不要手动调整这些生成代码,防止前端界面更新迭代时覆盖手动调整的内容。

推荐采用方式③进行前端界面开发,在此基础上探索wxWidgets项目的最佳开发流程。本文示例代码也可以作为wxWidgets项目的开发模板。

基本项目配置

  • 新建VC+ +空项目
  • 设置“配置属性——链接器——系统——子系统”为“窗口 (/SUBSYSTEM:WINDOWS)”
  • 导入wxWidgets-3.2.4\wxwidgets.props项目配置文件,无需手动设置头文件路径和依赖库
  • 新建main.cpp文件,定义wxApp的派生类(程序启动类)
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "wx/wx.h"

class MyApp :public wxApp {
public:
virtual bool OnInit();
};
wxIMPLEMENT_APP(MyApp);

bool MyApp::OnInit() {
if (!wxApp::OnInit())
return false;
return true;
}

wxFormBuilder设计GUI

  • 新建wxFormBuilder项目,设置文件名,设置生成XRC文件

  • 设计窗体

  • 生成XRC代码

将XRC编译成C+ +代码

wxWidgets源码安装路径下有XRC编译器源码(wxWidgets-3.2.4\utils\wxrc\),需要手动编译,编译完成之后得到wxrc.exe可执行文件。

  1. wxrc.exe基本用法

    • wxrc.exe -c:将XRC编译成C+ +源文件,用来替代XRC文件

    • wxrc.exe -c -e:除了生成上述C+ +源文件外,还可以生成额外的头文件,头文件中已经获得了各控件的指针变量。

  2. 编译XRC:wxrc.exe -c -e resource.xrc

  3. 项目生成时自动编译XRC:设置xrc文件的配置属性,添加自定义生成工具,这样项目重新生成时可根据文件是否更新来选择是否重新编译xrc文件。

命令行:D:\wxWidgets-3.2.4\utils\wxrc\vc_x64_mswu\wxrc.exe -c -e %(FullPath) .%(Filename).xrc

输出:%(Filename).h;%(Filename).cpp

引入C+ +代码并扩展窗体类

从xrc文件编译而来的头文件和源文件中不包含事件绑定、事件处理等代码,如果开发者直接在生成代码中添加这些逻辑,这些手动修改的内容会在下次重新编译XRC文件后被覆盖,因此禁止手动修改生成代码,可在新的代码文件中继承生成代码中的窗体类来添加这些额外逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#pragma once
#include "wx/wx.h"
#include "wx/xrc/xmlres.h"
#include "resource.h"

class MyDialog2Derived :public MyDialog2
{
public:
MyDialog2Derived() :MyDialog2(nullptr) {
// 绑定按钮事件
m_btnAdd->Bind(wxEVT_BUTTON, &MyDialog2Derived::OnAdd, this);
m_btnSubtract->Bind(wxEVT_BUTTON, &MyDialog2Derived::OnSubtract, this);
m_btnExit->Bind(wxEVT_BUTTON, &MyDialog2Derived::OnExit, this);

m_button7->Bind(wxEVT_BUTTON, &MyDialog2Derived::OnExit, this);
}

/// @brief 加运算
/// @param event
void OnAdd(wxCommandEvent& event) {
double num1, num2;
if (!m_textNum1->GetValue().ToDouble(&num1) || !m_textNum2->GetValue().ToDouble(&num2))
{
m_textRes->SetValue("");
wxMessageBox("操作数非法,请重新输入!", "温馨提示", wxOK | wxICON_ERROR);
return;
}

double res = num1 + num2;
m_textRes->SetValue(wxString::Format("%.3f",res));
}

/// @brief 减运算
/// @param event
void OnSubtract(wxCommandEvent& event) {
double num1, num2;
if (!m_textNum1->GetValue().ToDouble(&num1) || !m_textNum2->GetValue().ToDouble(&num2))
{
m_textRes->SetValue("");
wxMessageBox("操作数非法,请重新输入!", "温馨提示", wxOK | wxICON_ERROR);
return;
}

double res = num1 - num2;
m_textRes->SetValue(wxString::Format("%.3f", res));
}

/// @brief 退出事件
/// @param event
void OnExit(wxCommandEvent& event) {
Close(true);
}
};

同时,要更新MyApp类的内容:加载资源、创建顶层窗体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "wx/wx.h"
#include "wx/xrc/xmlres.h"

#include "resource.h"
#include "MyDialog2Derived.h"

class MyApp :public wxApp {
public:
virtual bool OnInit();

private:
MyDialog2Derived* dlg;

public:
};
wxIMPLEMENT_APP(MyApp);

bool MyApp::OnInit() {
if (!wxApp::OnInit())
return false;

wxXmlResource::Get()->InitAllHandlers();
InitXmlResource();

dlg = new MyDialog2Derived();
dlg->ShowModal();
dlg->Destroy();

return true;
}

将变化点限制在GUI设计

流程总结:使用wxFormBuilder设计界面生成xrc文件;将xrc编译成C+ +头文件和源文件;引用生成的C+ +代码,派生其窗体类,在子类中实现窗体的事件处理逻辑;在App类的OnInit()函数中创建子类实例,运行之。

在业务开发过程中,当前端界面GUI发生变化时,只需要在wxFormBuilder中重新生成xrc文件,然后重新编译项目即可。这种xrc自动编译、派生类机制将变化点限值在GUI设计,避免了工具自动生成代码和手动调整代码之间的矛盾性,从而保证了开发工作的连贯性。

评论