与传统c程序或Win32程序相比,wxWidgets最大的不同是贯彻了彻底的面向对象设计思想,所有的实体都被封装为类。应用程序本身也被定义为一个类进行管理。
创建wxWidgets应用程序最基础的方式是创建一个wxApp或wxAppConsole的派生类,然后重写其中的OnInit()方法。
以控制台程序为例,首先从wxAppConsole派生子类(如MyApp)。这个子类至少需要重写虚函数OnInit()。其返回参数是一个bool值,用于指示处理是否应继续(true)或直接退出(false)。
新建应用程序头文件myapp.h,声明wxAppConsole的派生子类MyApp,继承基本接口OnInit()和OnRun()。并调用宏wxDECLARE_APP()创建MyApp实例。
//MyApp.h
class MyApp : public wxAppConsole{
public:
virtual bool OnInit(); //初始化函数
virtual int OnRun(); //主程序函数
};
wxDECLARE_APP(MyApp);
新建应用程序实现文件myapp.cpp。使用wxIMPLEMENT_APP(MyApp)实现C程序运行相关的函数如main()等,并在main中对wxDECLARE_APP()创建的MyApp实例进行初始化等操作。
//MyApp.cpp
#include<iostream>
using namespace std;
//通过宏的方式创建MyApp全局对象和main()函数
wxIMPLEMENT_APP_CONSOLE(MyApp);
bool MyApp::OnInit(){
cout<<"Hello World"<<endl;
return true; //返回false将直接退出,不会执行后面的OnRun函数
}
int MyApp::OnRun(){
//主程序函数 do nothing
return 0;
}
至此,一个完整可运行的应用程序便诞生了。它会打开一个命令行窗口,然后输出字符串“Hello World”。
与控制台程序不同的是,GUI应用程序需要从wxApp类继承,在通常情况下,子类成员函数OnInit()的任务是创建顶层窗口。
如创建控制台程序一样,先创建头文件myapp.h。
//MyApp.h
class MyApp : public wxApp{
public:
virtual bool OnInit();
};
wxDECLARE_APP(MyApp);
创建定义文件
//MyApp.cpp
//通过宏的方式创建MyApp全局对象表示当前的应用程序
wxIMPLEMENT_APP(MyApp);
bool MyApp::OnInit(){
wxFrame *the_frame = new wxFrame(NULL, wxID_ANY, "minpro");
the_frame->Show(true);
return true;
}
该代码将显示一个非常简单的窗口。
wxAppConsole是wxApp的父类,成员函数bool OnInit()是入口函数,类似(但不等同)传统C/C++程序的main()。应用程序类存在于所有的wxWidgets应用程序中,是基于wxWidgets开发的起点,因此,对它进行深入地理解是必要而有意义的。其静态类结构如图 15所示。

图 15 wxApp类图
wxAppConsole继承至wxEventHandler(事件处理)和wxEvtFilter(事件过滤)。该类适用于编写控制台或wxUSE_GUI=0的混合应用程序,其作用为:设置和获取应用程序范围内的属性;实现窗口系统消息或事件循环,在控制台模式应用程序中也支持事件处理;通过OnInit()初始化应用程序;处理应用程序中其他模块未处理的事件等。
wxApp继承至wxAppConsole。适用于编写GUI应用程序。除了wxAppConsole提供的功能外,它还跟踪顶部窗口,添加了对视频模式的支持,并存储GUI应用程序的全局配置信息等。
wxEventHandler是用于处理事件。当接收到事件时,wxEvtHandler将调用事件表中的处理函数。当使用多重继承时,wxEvtHandler或其派生类类必须是继承的第一个类,以便整个对象的this指针与wxEvtHandler部分的this指针相同。
wxEvtFilter是一个全局事件过滤器,用于对程序中生成的所有事件进行预处理。这是一个非常简单的类,它只提供FilterEvent()虚拟方法,在启动任何事件处理之前先由wxEvtHandler处理。从这个类继承并重写FilterEvent()允许捕获所有事件,并可以决定处理或忽略这些事件。
应用程序入口类是一个派生至wxApp或wxAppConsole的C++类,如实例中的类MyApp。MyApp的创建由宏wxIMPLEMENT_APP(MyApp)完成,宏的参数为应用程序类的名称,创建过程如图 16所示。

图 16 wxIMPLEMENT_APP定义
wxIMPLEMENT_APP中的wxIMPLEMENT_APP_NO_THEMES负责实例化MyApp对象并创建全局变量wxTheApp;wxIMPLEMENT_APP_NO_THEMES主要完成两项工作:
一是根据平台类型创建main()。在不同的平台中,main的定义形式不尽相同,例如,wxMSW使用WinMain()替代main()。但它们最终都是由main()驱动。
二是创建2个全局函数wxCreateApp()和wxGetApp()以及1个全局wxAppInitializer变量wxTheAppInitializer。wxCreateApp()的功能是创建一个MyApp类型实例,wxGetApp()则返回这个实例。wxTheAppInitializer在构造函数将调用wxCreateApp()创建MyApp实例。
当wxWidgets创建MyApp实例时,会将实例的值赋给一个wxApp类型全局变量wxTheApp。您可以在程序中的任何位置引用这个变量,如(MyApp)wxTheApp。不过,使用wxGetApp()可以避免繁琐的类型转换,前提是需要通过wxDECLARE_APP(MyApp)来声明,其定义如下:
#define wxDECLARE_APP(appname)
extern appname& wxGetApp()
wxIMPLEMENT_APP(MyApp)定义了MyApp实例,并创建了main()调用MyApp实例启动程序。图 17为main()函数执行过程中涉及的主要函数及相互调用关系。

图 17 wxMSW中main函数流程
OnInit()是您会需要重写的一个函数,用于应用程序的初始化,main()在调用wxTheApp->OnInit()之前,wxWidgets的主要工作是为程序的运行准备运行时环境;OnRun()最后执行,持续进行事件分发和处理,wxWidgets应用程序是由事件驱动的。
命令参数在程序启动前传入,用于动态修改程序配置,定义程序行为。与int main(int argc,char**argv)不同,wxWidgets程序不能从OnInit()函数中直接获取命令行参数。argc和argv参数存储在wxAppConsole的同名成员变量中,并在调用OnInit()之前完成初始化。您可以在wxApp子类中直接使用,也可以在wxApp类之外通过wxGetApp().argc或wxGetApp().argv访问。
应用程序退出前应销毁所有的窗口。删除父窗口时会自动删除子窗口,因此建议在创建新窗口时应当尽可能标识窗口之间的父子关系。也可以在父窗口的wxCloseEvent处理函数中的显式删除所有子窗口。
在紧急情况下,可以调用wxExit()函数来结束应用程序,函数会删除顶层窗口及其子窗口,然后退出程序,但应该尽量避免使用这种结束程序的方式。
应用程序通常在最后一个顶层窗口关闭时自动退出。如果您的程序有一个顶层窗口,那么响应“Exit”菜单命令就可以调用wxWindow::Close()。如果调用了wxApp的SetExitOnFrameDelete(false)将禁用该功能,即最后一个顶层窗口关闭时,应用程序将会继续运行。
应用程序关闭过程中,会在销毁之前调用OnExit(),所有清理内存的工作通常在该函数中进行。您需要重载它以删除创建的wxWidgets对象。值得注意的是,不要从应用程序类的析构函数中销毁它们!例如,此代码可能会崩溃:
class MyApp : public wxApp{
public:
wxCHMHelpController m_helpCtrl;
//...
};
原因是m_helpCtrl是栈上分配的对象,将在MyApp析构函数中销毁,当调用MyApp的析构函数时,wxWidgets内部结构已经清理,此时调用wxCHMHelpController的析构函数会因为缺少必要的wxWidgets内部依赖而使应用崩溃。解决办法是在堆上创建wxWidgets对象,在MyApp::OnExit()删除:
class MyApp : public wxApp{
public:
wxCHMHelpController *m_helpCtrl;
//...
};
bool MyApp::OnInit(){
...
m_helpCtrl = new wxCHMHelpController;
//...
}
int MyApp::OnExit(){
delete m_helpCtrl;
return 0;
}
与MFC程序相比,wxWidgets贯彻了较为彻底的面向对象思想,程序结构简洁且易于理解。创建wxWidgets应用程序最基础的操作就是定义并创建一个wxApp的派生类即可。