wxWidgets学习笔记(一):解读Code::Blocks模板工程源代码

一、开发环境

  • 操作系统:Fedora 23
  • 集成开发环境:Code::Blocks 16.01
  • G++版本:5.3.1
  • GTK+版本:2.24.30(使用命令sudo dnf install gtk2 gtk2-devel gtk2-devel-docs安装)
  • wxWidgets版本:3.1.0(解压源码包后进入顶层目录依次输入./configuremakesudo make install三条命令)

二、新建wxWidgets模板工程

1、新建一个wxWidgets模板工程:
wxWidgets学习笔记(一):解读Code::Blocks模板工程源代码_第1张图片

2、选择好wxWidgets版本后给新建的工程命名,并且选择保存工程的路径:
wxWidgets学习笔记(一):解读Code::Blocks模板工程源代码_第2张图片

3、输入版权信息后选择模板工程的类型:
wxWidgets学习笔记(一):解读Code::Blocks模板工程源代码_第3张图片

4、配置编译器:
wxWidgets学习笔记(一):解读Code::Blocks模板工程源代码_第4张图片

5、配置wxWidgets工程,并且完成模板工程的建立:
wxWidgets学习笔记(一):解读Code::Blocks模板工程源代码_第5张图片

三、解读模板工程源代码

1、要使一个wxWidgets应用程序运行起来,首先应该定义一个wxApp类的子类,并且重载wxApp::OnInit函数。因为wxWidgets应用程序没有主函数,取而代之的是在wxApp类中定义的成员函数“wxApp::OnInit”,而且wxApp类中的成员函数可以使用argc和argv两个命令行参数。使用wxApp类需要包含头文件wx/app.h,由wxApp类派生出的子类在TemplateApp.h文件中定义,该子类中还声明了一个返回布尔值的虚函数OnInit(),该布尔值如果为true,则表明成功初始化。

/***************************************************************
 * Name:      TemplateApp.h
 * Purpose:   Defines Application Class
 * Author:    charmingsun ([email protected])
 * Created:   2016-06-08
 * Copyright: charmingsun (NULL)
 * License:
 **************************************************************/

#ifndef TEMPLATEAPP_H
#define TEMPLATEAPP_H

#include 

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

#endif // TEMPLATEAPP_H

2、wxApp子类中OnInit函数的定义在TemplateApp.cpp文件中,所以该文件包含了头文件TemplateApp.hTemplateApp.cpp文件首先使用IMPLEMENT_APP(TemplateApp)或者wxIMPLEMENT_APP(TemplateApp);宏来动态地创建并启动上述wxApp子类的实例(该宏后面必须加分号)。

然后该文件才定义了wxApp子类的OnInit函数。因为在wxApp子类的OnInit函数中必须包含一个顶级的wxFrame类或者wxDialog类窗口,所以该OnInit函数内的第一条语句就定义了一个名为frame的TemplateFrame类的实例,TemplateFrame类为wxFrame类的子类,该子类将在TemplateMain.h文件中定义,所以该TemplateApp.cpp文件应该包含TemplateMain.h这个头文件。该语句向frame实例的构造函数传递了两个参数,第一个为long类型的值0,即第一个参数为空NULL,第二个参数为_(“wxWidgets Application Template”)函数的返回值,_()宏与wxGetTranslation()函数等价,将输入的const char *类型的字符串转化为wxString类型的字符串输出。

该OnInit函数内的第二条语句显式地调用了TemplateFrame类的frame实例的Show()函数,该Show()函数继承了TemplateFrame类的wxWindow基类的Show()函数,Show()函数应该在窗口类被创建之后立即被调用,使刚刚被创建的窗口显示出来,Show()函数的默认输入参数为true,即为显示窗口,false为隐藏窗口。最后该OnInit函数最后一条语句返回了true值,表明初始化成功。

*注:有关该TemplateApp.cpp文件开始的两段预编译指令的说明:第一段告诉编译器如果该平台支持预编译的头文件,则包含wx_pch.h这个头文件;第二段告诉编译器如果使用的是Borland公司的C++ Builder的IDE,则表明该预编译指令之前包含的所有头文件使用预编译的头文件以节省编译时间。

/***************************************************************
 * Name:      TemplateApp.cpp
 * Purpose:   Code for Application Class
 * Author:    charmingsun ([email protected])
 * Created:   2016-06-08
 * Copyright: charmingsun (NULL)
 * License:
 **************************************************************/

#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__

#include "TemplateApp.h"
#include "TemplateMain.h"

IMPLEMENT_APP(TemplateApp);

bool TemplateApp::OnInit()
{
    TemplateFrame* frame = new TemplateFrame(0L, _("wxWidgets Application Template"));

    frame->Show();

    return true;
}

3、接下来在TemplateMain.h文件中定义了wxFrame类的子类——TemplateFrame类,可以不包含TemplateApp.h头文件。TemplateFrame类首先声明了该类的构造函数和析构函数这两个公有成员函数。然后使用枚举类型定义了idMenuQuit和idMenuAbout这两个私有成员常量,这两个常量为产生命令的菜单项的标识符,将在TemplateFrame窗口类的事件表以及构造函数中用到。

然后定义了一个名为OnClose的事件处理函数,该函数输入一个wxCloseEvent事件类,该类包含关闭窗口和会话事件的一些信息。然后定义了一个名为OnQuit和一个名为OnAbout的事件处理函数,这两个函数都输入一个wxCommandEvent事件类,该类包含命令事件的一些信息。这些事件处理函数所返回的信息由输入参数传递,而且通常不会被外部类调用,所以返回值为空,而且通常被声明为私有成员函数。事件处理函数通常以OnSomething();的格式命名,但是也没有规定一定要按照这个格式命名。

最后,在TemplateFrame类的末尾插入了一个名为DECLARE_EVENT_TABLE()的宏(该宏等同于wxDECLARE_EVENT_TABLE();宏),这个宏为该类声明了一个静态的事件表来处理事件。这个宏可以放在处理事件的类的任何位置,但是习惯上放在类的末尾。因为这个宏会从内部改变访问类型,所以放在类的末尾最为安全。处理事件的类必须由wxEvtHandler类派生而来,而wxWindow类是从wxEvtHandler类派生出来的,所以任何由wxWindow类派生出来的类都可以接收并处理事件,比如wxFrame类和wxDialog类。

/***************************************************************
 * Name:      TemplateMain.h
 * Purpose:   Defines Application Frame
 * Author:    charmingsun ([email protected])
 * Created:   2016-06-08
 * Copyright: charmingsun (NULL)
 * License:
 **************************************************************/

#ifndef TEMPLATEMAIN_H
#define TEMPLATEMAIN_H

#ifndef WX_PRECOMP
    #include 
#endif

#include "TemplateApp.h"

class TemplateFrame: public wxFrame
{
    public:
        TemplateFrame(wxFrame *frame, const wxString& title);
        ~TemplateFrame();
    private:
        enum
        {
            idMenuQuit = 1000,
            idMenuAbout
        };
        void OnClose(wxCloseEvent& event);
        void OnQuit(wxCommandEvent& event);
        void OnAbout(wxCommandEvent& event);
        DECLARE_EVENT_TABLE()
};

#endif // TEMPLATEMAIN_H

4、TemplateMain.cpp文件定义了TemplateFrame类中的事件表和事件处理函数。该文件首先定义了一个名为wxbuildinfo的帮助函数,该函数用于TemplateFrame类的构造函数以及名为OnAbout的事件处理函数。该wxbuildinfo函数输入一个名为wxbuildinfoformat的枚举类型的值,如果输入为short_f,则该函数以wxString类型返回wxWidgets的版本号,如果输入为long_f,则该函数以wxString类型返回wxWidgets的版本号、操作系统平台以及是使用的Unicode编码还是ANSI编码。

然后该文件才定义了TemplateFrame类中的事件表,该事件表告诉wxWidgets事件要怎样映射到负责处理事件的函数上。事件表由wxBEGIN_EVENT_TABLE()和wxEND_EVENT_TABLE()这两个宏以及两个宏之间的EVT_xxx宏组成。wxBEGIN_EVENT_TABLE(theClass,baseClass)宏的第一个参数为需要捕获事件的类,第二个参数为需要捕获事件的类的基类,wxEND_EVENT_TABLE()宏没有参数,EVT_xxx宏将事件重定向至参数中的成员函数。EVT_CLOSE(TemplateFrame::OnClose)宏属于wxCloseEvent类,该宏将命令事件wxEVT_CLOSE_WINDOW事件重定向至TemplateFrame类中的OnClose成员函数。EVT_MENU(id, func)宏属于wxCommandEvent类,第一个参数为产生wxEVT_MENU命令的菜单项的标识符,第二个参数为处理wxEVT_MENU命令的成员函数。

然后该文件定义了TemplateFrame类的构造函数,该构造函数的总参数表中的两个参数将传递给TemplateFrame类的基类的构造函数wxFrame::wxFrame(wxWindow * parent , wxWindowID id , const wxString & title , const wxPoint & pos = wxDefaultPosition , const wxSize & size = wxDefaultSize , long style = wxDEFAULT_FRAME_STYLE , const wxString & name = wxFrameNameStr),wxFrame类的第一个参数为该窗口的父类,第二个参数为该窗口的标识符(默认值为-1),第三个参数为该窗口的标题。

该TemplateFrame类的构造函数内的第一个预编译指令包含的代码创建了一个菜单栏。点击类名阅读wxMenu类和wxMenuBar类的在线参考手册,请根据参考手册自行理解源代码。其中_T()宏将将输入的const char *类型的字符串转化为Unicode编码的字符串输出,详情请点击名称阅读该宏的在线参考手册。其中SetMenuBar(mbar);语句调用了wxFrame类中的SetMenuBar()函数,这个函数告诉wxWidgets框架显示由参数传入的菜单栏。

该TemplateFrame类的构造函数内的第二个预编译指令包含的代码创建了一个状态栏。其中CreateStatusBar(2);语句创建了一个两个分区的状态栏,SetStatusText(_(“Hello Code::Blocks user!”),0);语句设置了状态栏第一个分区内的文本并且重绘了状态栏,SetStatusText(wxbuildinfo(short_f), 1);语句设置了状态栏第二个分区内的文本并且重绘了状态栏。更多信息请点击类名阅读wxFrame类的在线参考手册。

最后该文件定义了TemplateFrame类的析构函数、OnClose事件处理函数、OnQuit事件处理函数以及OnAbout事件处理函数。使用virtual bool wxWindow::Destroy()函数安全地注销窗口。使用wxMessageBox(msg, _(“Welcome to…”));语句创建一个标题为“Welcome to…”内容为“wxWidgets 3.1.0-Linux-Unicode build”的对话框。有关wxMessageBox函数的更多信息请点击函数名阅读在线参考手册。

/***************************************************************
 * Name:      TemplateMain.cpp
 * Purpose:   Code for Application Frame
 * Author:    charmingsun ([email protected])
 * Created:   2016-06-08
 * Copyright: charmingsun (NULL)
 * License:
 **************************************************************/

#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__

#include "TemplateMain.h"

//helper functions
enum wxbuildinfoformat {
    short_f, long_f };

wxString wxbuildinfo(wxbuildinfoformat format)
{
    wxString wxbuild(wxVERSION_STRING);

    if (format == long_f )
    {
#if defined(__WXMSW__)
        wxbuild << _T("-Windows");
#elif defined(__WXMAC__)
        wxbuild << _T("-Mac");
#elif defined(__UNIX__)
        wxbuild << _T("-Linux");
#endif

#if wxUSE_UNICODE
        wxbuild << _T("-Unicode build");
#else
        wxbuild << _T("-ANSI build");
#endif // wxUSE_UNICODE
    }

    return wxbuild;
}

BEGIN_EVENT_TABLE(TemplateFrame, wxFrame)
    EVT_CLOSE(TemplateFrame::OnClose)
    EVT_MENU(idMenuQuit, TemplateFrame::OnQuit)
    EVT_MENU(idMenuAbout, TemplateFrame::OnAbout)
END_EVENT_TABLE()

TemplateFrame::TemplateFrame(wxFrame *frame, const wxString& title)
    : wxFrame(frame, -1, title)
{
#if wxUSE_MENUS
    // create a menu bar
    wxMenuBar* mbar = new wxMenuBar();
    wxMenu* fileMenu = new wxMenu(_T(""));
    fileMenu->Append(idMenuQuit, _("&Quit\tAlt-F4"), _("Quit the application"));
    mbar->Append(fileMenu, _("&File"));

    wxMenu* helpMenu = new wxMenu(_T(""));
    helpMenu->Append(idMenuAbout, _("&About\tF1"), _("Show info about this application"));
    mbar->Append(helpMenu, _("&Help"));

    SetMenuBar(mbar);
#endif // wxUSE_MENUS

#if wxUSE_STATUSBAR
    // create a status bar with some information about the used wxWidgets version
    CreateStatusBar(2);
    SetStatusText(_("Hello Code::Blocks user!"),0);
    SetStatusText(wxbuildinfo(short_f), 1);
#endif // wxUSE_STATUSBAR

}

TemplateFrame::~TemplateFrame()
{
}

void TemplateFrame::OnClose(wxCloseEvent &event)
{
    Destroy();
}

void TemplateFrame::OnQuit(wxCommandEvent &event)
{
    Destroy();
}

void TemplateFrame::OnAbout(wxCommandEvent &event)
{
    wxString msg = wxbuildinfo(long_f);
    wxMessageBox(msg, _("Welcome to..."));
}

四、进一步学习

wxWidgets: Hello World Example
wxWidgets: A Quick Guide to Writing Applications
wxWidgets: Programming Guides
wxWidgets tutorial

你可能感兴趣的:(wxWidgets)