使用wxWidgets进行跨平台的C++开发

简介:
本文阐述了 wxWidgets 的由来,以及从 wxWidgets 的特点出发,说明了选择 wxWidgets 给我们带来的好处,并且通过一个典型的例子讨论了如何在 C++ 中使用 wxWidgets 开发跨平台的软件。
什么是 wxWidgets
wxWidgets 是一个跨平台的软件开发包。它诞生于 1992 年,最初的名子是 wxWindows ,但由于 Microsoft 的抗议,在 2004 年改名为 wxWidgets 。它最初是被设计成跨平台的 GUI 软件开发包,但后来随着越来越多的人参与进来,为 wxWidgets 加入了许多非 GUI 的功能,如多线程 (MultiThread) 、网络 (Network) 等。并且从最初的只支持 C++ 语言,逐渐发展成为支持数种语言(如 Python Perl C# Basic 等)。因此,现在的 wxWidgets 已经不再是单纯的跨平台的 GUI 软件开发包,而是一个可以支持多种操作系统平台的能够在多种语言中使用的通用跨平台软件开发包。
由于 wxWidgets 最开始是为 C++ 而设计的,因此,本文主要讨论了 wxWidgets C++ 中的使用。
为什么选择 wxWidgets
目前支持 C++ 的软件开发包非常多,比较有名的除了 wxWidgets 外,还有一些其它的软件开发包,如 MFC QT ACE 等。即然有这么多开发包,那么我们为什么要使用 wxWidgets 呢?在给出答案之前,让我们首先来看一看上述的三种软件开发包的特性。
1.        MFC
MFC Microsoft 提供的软件开发包。 MFC 虽然十分强大,但它只能运行在 Windows 下运行。而且它是收费的。
2.  QT
QT 是由Trolltech  公司开发的一套跨平台软件开发包。它和wxWidgets 类似,但是QT 只在linux 下免费,而在Windows Unix 下使用QT 要向Trolltech 公司支付版权费。
3.  ACE
ACE 虽然是免费开源的,但是它没有提供 GUI 功能。

    从以上三个软件开发包可以看出,它们虽然有各自的优势,但是它们或多或少地都会使开发受到限制。而使用wxWidgets将不会有以上所述的问题。wxWidgets和MFC、QT、
 ACE的特性对比如表1所示。
表1: wxWidgets和MFC、QT、ACE的特性对比表
     注:其中免费中的“是 / 否”代表 QT linux 平台上的 Free Edition 是免费的,而在 windows unix 下使用 QT 是收费的。而开源中的“是 / 否”代表 QT 有一个基于 GPL 的开源版本,但要进行商业开发,需要使用它的商业版本。
使用 wxWidgets 编写程序
学习一种编程语言的最好方法就是用它去编写程序,学习 wxWidgets 也不例外。由于 wxWidgets 的主要功能是实现跨平台的 GUI ,因此,本文主要从 GUI 入手,讨论 wxWidgets C++ 中如何编写跨平台的应用程序
1.  应用程序类的建立
使用 wxWidgets 建立系统需要一个类来描述整个应用程序。这个类必须从 wxApp 类继承。
class  MyApp :  public  wxApp    // 应用程序类
{
public :
    
virtual   bool  OnInit();  //  在应用程序启动时调用,如果返回false,退出应用程序
};
这个类只覆盖了 wxApp 的一个虚方法 OnInit 。可以用这个方法在程序启动时做一些验证,如果验证失败,可以通过返回 false 退出应用程序。当然,由于这个函数是应用程序的入口点,所以建立主窗体的工作要在这个函数中完成。
2.  建立窗体类
    wxWidgets 中关于窗体的类很多,如果要建立一般窗体的话,可以从 wxFrame 继承。 
class  MyFrame :  public  wxFrame  // 窗体类
{
public :
    MyFrame(
const  wxString &  title);  //  窗体的构造函数
};
3.  向窗体中加入控件
    在本文中向这个窗体加入了一个菜单条 (Menu Bar) 、一个状态条、一个 Panel 和一个按钮。一般我们会在主窗体的构造函数中加入这些控件。 
MyFrame::MyFrame( const  wxString &  title) : wxFrame(NULL, wxID_ANY, title)
{
    wxMenu 
* fileMenu  =   new  wxMenu;   //  建立“文件”菜单 
    wxMenu  * helpMenu  =   new  wxMenu;  //  建立“帮助”菜单
    
//  向菜单中添加子项
    helpMenu
-> Append(wxID_ABOUT, _T( " 关于\tF1 " ), _T( " 显示关于对话框 " ));
    fileMenu
-> Append(wxID_EXIT, _T( " 退出\tAlt-X " ), _T( " 退出应用程序 " ));
    wxMenuBar 
* menuBar  =   new  wxMenuBar();   //  建立一个菜单条
    menuBar -> Append(fileMenu, _T( " 文件 " ));   // 将“文件”菜单加入到菜单条
    menuBar -> Append(helpMenu, _T( " 帮助 " ));   // 将“帮助”菜单加入到菜单条
    SetMenuBar(menuBar);   // 将菜单条放到窗体上
    wxPanel  * panel  =   new  wxPanel( this );    // 建立一个Panel
    wxButton  * button  =   new  wxButton(panel, wxID_ABOUT,  " 关于 " , wxPoint( 20 20 ), wxSize( 50 30 ));   // 建立一个Button
    CreateStatusBar( 2 );   // 建立一个两栏的状态栏
    SetStatusText(_T( " 欢迎使用wxWidgets! " ));   // 设置状态栏的文本
     在数组 sample_xpm 中描述了 sample.ico 的属性和图标本身。如 X 代表红色;  o 代表黄色等。然后在源程序中通过 include “sample.xpm” 引用这个资源文件。要想从这个资源文件中装载图标。可使用 SetIcon(wxICON(sample)); wxICON 读取资源文件,而 SetIcon 将这个图标设置为 frame 的标题栏图标。要想将 ico 文件转换为这种资源文件,可使用一个免费软件XnView 进行转换。
5.  显示主窗体
    显示主窗体非常简单,只需要将上面建立的 MyFrame 类实例化,并调用 wxFrame Show 方法显示即可。这些代码可以写在 MyApp 类的 OnInit 方法中。
bool  MyApp::OnInit()
{
    
// 建立MyFrame类的实例
    MyFrame  * frame  =   new  MyFrame(_T( " 第一个wxWidgets程序 " ));
    frame
-> Show( true );   // 显示主窗体
     return   true ;   // 必须返回true,否则应用程序将退出
}
在以上代码中 Show 方法有一个参数,如果为 true ,则以模式窗口的形式显示,否则以非模式窗口的形式显示。
6.  向窗体中加入事件
到目前为止,这个程序的界面已经完成了,但还未响应任何事件,下面就详细阐述如何向这个应用程序中加入事件代码。
    对于事件来说,一般都会由两部分组成。
(1) 调用事件部分
当程序发生某个动作时,如点击按钮;选中某个控件,可能需要执行一段代码。而这段代码一般是由系统负责调用的,也就是说系统通过事件函数指针调用相应的代码。
(2) 事件函数本身
    事件函数与普通函数一样,只不过它是在发生了事件之后,由系统调用的。  

wxWidgets 中是通过事件哈希表 (Event Hash Table) 来进行事件处理的,即将相应的事件函数指针保存在一个哈希表中,然后当事件发生时,从这个哈希表中找到相应的事件函数指针,然后通过函数指针调用函数。在使用事件哈希表之前,必须定义它。由于定义哈希表非常复杂,而且每个需要处理事件的类都需要同样的代码,因此, wxWidgets 为此定义了一个宏 DECLARE_EVENT_TABLE() 来定义哈希表。可将这个宏写在 MyFrame 类的任何位置。它相当于将以下语句放到了 MyFrame 类中。
     private :
       
static   const  wxEventTableEntry sm_eventTableEntries[]; 
    
protected
        
static   const  wxEventTable  sm_eventTable; 
        
virtual   const  wxEventTable *   GetEventTable()  const
        
static  wxEventHashTable  sm_eventHashTable;
        
virtual  wxEventHashTable &   GetEventHashTable()  const ;
其中静态数组变量 sm_eventTableEntries 保存了 MyFrame 类中的所有的事件信息。
上面的代码声明了处理事件哈希表的一些方法,即然声明了,就得实现。由于实现代码也都一样,因此, wxWidgets 也为实现这些方法定义了一组宏。实现这些方法的宏如下所示。
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(wxID_EXIT,  MyFrame::OnQuit)
    EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
    EVT_BUTTON(wxID_ABOUT, MyFrame::OnAbout)
END_EVENT_TABLE()
    其中 BEGIN_EVENT_TABLE(…) 实现了上面定义的方法,以及初始化了静态变量 sm_eventTable 。后面两个 EVT_MENU 和一个 EVT_BUTTON 宏初始化了静态变量 sm_eventTableEntries ,即将这两个事件函数的指针 (button about 菜单使用一个事件函数 OnAbout) 和控件 ID 保存在 sm_eventTableEntries 中,最后的 END_EVENT_TABLE() 宏做为一个空的事件函数指针赋给了 sm_eventTableEntries ,这有些象 C 语言中处理字符串,将最后一个字符赋为 ’"0’ ,这样就可以知道哪是结尾了。
    向窗体中加入事件的最后一步是声明和实现事件函数。在本例中声明了两个事件函数。
 
void  OnQuit(wxCommandEvent &   event );
void  OnAbout(wxCommandEvent &   event );
可以将这两个函数声明放到 MyFrame 中的任何位置。下面是它们的实现代码。
void  MyFrame::OnQuit(wxCommandEvent &  WXUNUSED( event ))
{  
    Close(
true );
}
void  MyFrame::OnAbout(wxCommandEvent &  WXUNUSED( event ))
{
    wxString msg;
    msg.Printf( _T(
" 这是一个关于对话框的例子.\n " )
                _T(
" 欢迎使用 %s " ), wxVERSION_STRING);
    wxMessageBox(msg, _T(
" ¹关于 " ), wxOK  |  wxICON_INFORMATION,  this );
}
其中 OnQuit 函数调用 Close(true) 关闭 MyFrame ,由于 MyFrame 是主窗体,因此,在 MyFrame 关闭后,应用程序也随之关闭了。 OnAbout 使用 wxMessageBox 函数弹出一个信息对话框。
7.   运行程序
到目前为止,这个程序的代码已经基本完成了,但是在前面曾说过, MyApp 中的 OnInit 方法在应用程序启动时执行,那么是谁调用了 OnInit 方法呢?答案当然是 wxWidgets wxWidgets 为了调用这个方法,提供了一个宏 IMPLEMENT_APP(…) ,这个宏有一个参数,需要将 MyApp 做为参数传入。即 IMPLEMENT_APP(MyApp) 。这个宏相当于一个 WinMain 函数(和控制台程序的 main 函数类似),即在 WinMain 函数中调用了 MyApp 中的 OnInit 函数。在加入这个宏后,就可使用一个 C++ 编译器将以上的源程序编译生成 exe 文件了。应用程序的界面如图 1 、图 2 所示。


图1 Windows下的程序界面




图2  Linux下的程序界面
注:在 windows 下使用的 wxWidgets 版本是 wxWidgets2.6.2 ,在 linux 下使用的 wxWidgets 版本号是 wxWidgets2.6.3 ,因此,在 windows linux 下的 wxVERSION_STRING 值不一样。
wxWidgets 的优势和不足
    通过上面的介绍,相信读者已经对如何使用 wxWidgets 编写 GUI 程序有了一定的了解。 wxWidgets 在开发跨平台的软件上有着许多其它软件开发包不具备的优势,下面就总结一下 wxWidgets 所具有的优势。 
        1.  跨平台

        wxWidgets
    支持非常多的操作系统平台,如 Windows Linux Unix 等。
    2.   丰富的组件
    wxWidgets 拥有上百个组件可供用户选择。有了这些组件,将会给我们带来更加丰富的用户体验。
    3.  支持多种语言
    wxWidgets 不仅可以在 C++ 中使用,而且也可以在其它语言中使用,这些语言包括 python perl c# 等。
    4.        使用本地控制
    从上面给出的两个应用程序界面可以看出,在 Windows Linux 下运行这个应用程序保持了各自的风格。这是因为 wxWidgets 采用了本地的 API ,而不象其它的跨平台库去模拟它们。因此,使用 wxWidgets 开发和在 Windows 下使用 Win32 API 或在 Linux 下使用 GTK 开发没有什么区别。
    5.  免费开源
    这个世界上免费的开发包很多,强大的开发包也很多,当然,开源的开发包就更多了。但是要想同时满足这三点:免费、开源、强大,又同时具有本地程序一样的性能,恐怕 wxWidgets 是唯一的选择,至少是最佳的选择。
    相信上面关于 wxWidgets 5 个优势已经足以成为我们选择它的理由了。也就是说,如果选择 wxWidgets ,不仅可以获得强大的功能、卓越的性能,而且您不必为此付一分钱。当然,人无完人、物无完物。 wxWidgets 也并不是没有缺点。下面就说一下 wxWidgets 的不足之处。
    1. IDE 支持不够
    对于 wxWidgets 来说,最大的优点也就是它最大的缺点。由于 wxWidgets 所提供的组件很多,但到现在为止还没有一个强大的 IDE 来支持它,这将给大型系统的开发带来麻烦。
    2.  对双字节字符的支持不理想
    wxWidgets 中的有些组件,如 xml 组件,无法识别双字节字符,如汉字会被认为是非法字符而无法装载 xml 文档。
    综合上述, wxWidgets 从总体上来说还是一个非常强大的跨平台软件开发包。如果您没有足够的资金来购买商业的软件开发包,也许 wxWidgets 是最好的选择。虽然 wxWidgets 也有一些不足,但这并不能阻碍 wxWidgets 的发展。 wxWidgets 的功能还很多,由于篇幅所限,本文只能从一个简单的例子来讨论如何用 wxWidgets 来开发一个跨平台的 GUI 程序,如果读者对 wxWidgets 感性趣,可以访问 http://www.wxWidgets.org 获得更多的信息。





     本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/215222,如需转载请自行联系原作者







    相关文章
    |
    3月前
    |
    机器学习/深度学习 算法 算法框架/工具
    为什么使用C++进行机器学习开发
    C++作为一种高性能语言,在某些性能要求极高或资源受限的场景下也具有非常重要的地位。C++的高效性和对底层硬件的控制能力,使其在大规模机器学习系统中发挥重要作用,尤其是当需要处理大数据或实时响应的系统时。
    61 3
    WK
    |
    1月前
    |
    开发框架 开发工具 C++
    C++跨平台框架Qt
    Qt是一个功能强大的C++跨平台应用程序开发框架,支持Windows、macOS、Linux、Android和iOS等操作系统。它提供了250多个C++类,涵盖GUI设计、数据库操作、网络编程等功能。Qt的核心特点是跨平台性、丰富的类库、信号与槽机制,以及良好的文档和社区支持。Qt Creator是其官方IDE,提供了一整套开发工具,方便创建、编译、调试和运行应用程序。Qt适用于桌面、嵌入式和移动应用开发。
    WK
    74 5
    WK
    |
    1月前
    |
    机器学习/深度学习 人工智能 算法
    那C++适合开发哪些项目
    C++ 是一种功能强大、应用广泛的编程语言,适合开发多种类型的项目。它在游戏开发、操作系统、嵌入式系统、科学计算、金融、图形图像处理、数据库管理、网络通信、人工智能、虚拟现实、航空航天等领域都有广泛应用。C++ 以其高性能、内存管理和跨平台兼容性等优势,成为众多开发者的选择。
    WK
    89 1
    |
    2月前
    |
    Rust 资源调度 安全
    为什么使用 Rust over C++ 进行 IoT 解决方案开发
    为什么使用 Rust over C++ 进行 IoT 解决方案开发
    95 7
    WK
    |
    1月前
    |
    C++ 开发者 iOS开发
    C++跨平台框架
    C++跨平台框架使开发者能够编写一次代码,在多个操作系统和硬件平台上运行,提高开发效率和软件可扩展性。常见的框架包括Qt、wxWidgets、SDL、JUCE等,它们各自具有丰富的功能和特点,适用于不同的应用场景。选择框架时需考虑目标平台、功能需求、学习曲线和社区支持等因素。
    WK
    61 0
    WK
    |
    1月前
    |
    开发框架 移动开发 Java
    C++和Java哪个更适合开发移动应用
    本文对比了C++和Java在移动应用开发中的优劣,从市场需求、学习难度、开发效率、跨平台性和应用领域等方面进行了详细分析。Java在Android开发中占据优势,而C++则适合对性能要求较高的场景。选择应根据具体需求和个人偏好综合考虑。
    WK
    64 0
    WK
    |
    1月前
    |
    安全 Java 编译器
    C++和Java哪个更适合开发web网站
    在Web开发领域,C++和Java各具优势。C++以其高性能、低级控制和跨平台性著称,适用于需要高吞吐量和低延迟的场景,如实时交易系统和在线游戏服务器。Java则凭借其跨平台性、丰富的生态系统和强大的安全性,广泛应用于企业级Web开发,如企业管理系统和电子商务平台。选择时需根据项目需求和技术储备综合考虑。
    WK
    114 0
    |
    3月前
    |
    编译器 API C语言
    超级好用的C++实用库之跨平台实用方法
    超级好用的C++实用库之跨平台实用方法
    46 6
    |
    2月前
    |
    NoSQL API Redis
    如何使用 C++ 开发 Redis 模块
    如何使用 C++ 开发 Redis 模块
    |
    3月前
    |
    物联网 C# C语言
    物联网开发中C、C++和C#哪个更好用
    在物联网(IoT)开发中,C、C++和C#各有优缺点,适用场景不同。C语言性能高、资源占用低,适合内存和计算能力有限的嵌入式系统,但开发复杂度高,易出错。C++支持面向对象编程,性能优秀,适用于复杂应用,但学习曲线陡峭,编译时间长。C#易于学习,与.NET框架结合紧密,适合快速开发Windows应用,但性能略低,平台支持有限。选择语言需根据具体项目需求、复杂性和团队技术栈综合考虑。