65.9K
CodeProject 正在变化。 阅读更多。
Home

wxWidgets 简介

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (119投票s)

2005年9月3日

GPL3

21分钟阅读

viewsIcon

1721700

downloadIcon

7220

wxWidgets 跨平台 GUI 开发初学者教程。

引言

wxWidgets,以前称为 wxWindows,是一个用 C++ 开发跨平台 GUI 应用程序的框架。Julian Smart 于 1992 年在爱丁堡大学人工智能应用研究所启动了这个框架。1995 年,Markus Holzem 发布了 Xt 端口。1997 年 5 月,Windows 和 GTK+ 端口合并并放入 CVS 存储库中。

什么是 wxWidgets

wxWidgets 提供了一个单一、易于使用的 API,用于在多个平台上编写 GUI 应用程序。将其与适用于您的平台(Windows/Unix/Mac)和编译器(几乎任何流行的 C++ 编译器)的相应库链接,您的应用程序将采用适合该平台的外观。除了强大的 GUI 功能外,wxWindows 还为您提供:在线帮助、网络编程、流、剪贴板和拖放、多线程、各种流行格式的图像加载和保存、数据库支持、HTML 查看和打印等等。

谁应该使用 wxWidgets

wxWidgets 是一个与 MFC 非常相似的框架,只是它有一些自身的缺点。那些了解 Linux 用户数量不断增长并希望编写跨平台 GUI 应用程序的 MFC 程序员可以使用 wxWidgets。使用 wxWidgets,基于 C++ 的框架非常容易使用,并且它有 13 年的良好记录。实际上,wxWidgets 非常稳定,并且支持

  • Windows 3.1、Windows 95/98、Windows NT、Windows 2000/XP、Windows ME、Windows CE。
  • 使用 GTK+ 的 Linux 和其他 UNIX 平台。
  • 使用 Motif 或免费 Motif 克隆 Lesstif 的 UNIX。
  • Mac OS。
  • 正在研究嵌入式平台。请参阅wxUniversal项目。
  • OS/2 端口正在开发中,您还可以为 OS/2 上的 GTK+ 或 Motif 编译 wxWidgets。

为什么使用 wxWidgets

有许多选项可用于编写跨平台 GUI 开发,例如:JAVA、Mono.NET、Qt 等。Java 未能证明自己是一种有效的替代方案。Qt 很好但商业化,没有人知道它的未来。Mono.NET 似乎不错,但在很大程度上由微软驱动,它看起来像是微软工作的复制品,并且尚未证明自己是一种成功的替代方案。此外,人们可能不喜欢为高效软件增加额外的层负担。由于 wxWidgets 不使用任何中间层,并且只使用平台上可用的原生控件,因此它为应用程序提供了美观的外观和感觉。

主要功能

  • 多线程。
  • 剪贴板和拖放。
  • 网络编程,例如:wxSMTPwxHTTPwxFTP
  • 各种流行格式的图像加载和保存。
  • 流(ZIP、网络、文件等),例如:wxRarInputStream
  • 数据库支持,例如:wxDao
  • HTML 查看和打印,例如:wxMozillawxIE
  • 基于 XML 的资源、多语言/Unicode 支持。
  • 操作系统提供的默认样式主题(例如:XP 样式主题)。

与 MFC 的相似性

MFC 和 wxWidgets 宏

MFC 版本 wxWidgets 版本
BEGIN_MESSAGE_MAP BEGIN_EVENT_TABLE
END_MESSAGE_MAP END_EVENT_TABLE
DECLARE_DYNAMIC DECLARE_CLASS
DECLARE_DYNCREATE DECLARE_DYNAMIC_CLASS
IMPLEMENT_DYNAMIC IMPLEMENT_CLASS
IMPLEMENT_DYNCREATE IMPLEMENT_DYNAMIC_CLASS
IsKindOf(RUNTIME_CLASS(CWindow)) IsKindOf(CLASSINFO(wxWindow))

MFC 和 wxWidgets 类

杂项类
MFC 版本 wxWidgets 版本
CWinApp wxApp
CObject wxObject
CCmdTarget wxEvtHandler
CCommandLineInfo wxCmdLineParser
CMenu wxMenuwMenuBarwxMenuItem
CWaitCursor wxBusyCursor
CDataExchange wxValidator
窗口类
MFC 版本 wxWidgets 版本
CFrameWnd wxFrame
CMDIFrameWnd wxMDIParentFrame
CMDIChildWnd wxMDIChildFrame
CSplitterWnd wxSplitterWindow
CToolBar wxToolBar
CStatusBar wxStatusBar
CReBar wxCoolBar,但请参阅 contrib/src/fl 和 wxAUIwxDockIt
CPropertyPage wxPanel
CPropertySheet wxNotebookwxPropertySheetDialog
对话框类
MFC 版本 wxWidgets 版本
CDialog wxDialog
CColorDialog wxColourDialog
CFileDialog wxFileDialog
CFindReplaceDialog wxFindReplaceDialog
CFontDialog wxFontDialog
CPageSetupDialog wxPageSetupDialog
CPrintDialog wxPrintDialog
控件类
MFC 版本 wxWidgets 版本
CAnimateCtrl wxMediaCtrl、wxAnimationCtrl
CButton wxButton
CBitmapButton wxBitmapButton
CComboBox wxComboBoxwxChoice
CDateTimeCtrl wxDatePickerCtrl
CEdit wxTextCtrl
CHotKeyCtrl 无,但请参阅 Keybinder
CListBoxCDragListBox wxListBox
CCheckListBox wxCheckListBox
CListCtrl wxListCtrlwxListView
CMonthCalCtrl wxCalendarCtrl
CProgressCtrl wxGauge
CReBarCtrl 无,但请参阅 contrib/src/fl 和 wxAUIwxDockIt
CRichEditCtrl wxTextCtrl
CScrollBar wxScrollBar
CSliderCtrl wxSlider
CSpinButtonCtrl wxSpinButtonwxSpinCtrl
CStatic wxStaticTextwxStaticLinewxStaticBoxwxStaticBitmap
CStatusBarCtrl wxStatusBar
CTabCtrl wxTabCtrl
CToolBarCtrl wxToolBar
CToolTipCtrl wxToolTip
CTreeCtrl wxTreeCtrl
图形类
MFC 版本 wxWidgets 版本
CBitmap wxBitmapwxImagewxIconwxCursor
CBrush wxBrush
CPen wxPen
CFont wxFont
CImageList wxImageListwxIconBundle
CPalette wxPalette
CRgn wxRegion
CClientDC wxClientDC
CMetaFileDC wxMetaFileDC
CPaintDC wxPaintDC
CWindowDC wxWindowDC
CDC wxDCwxMemoryDC
数据结构类
MFC 版本 wxWidgets 版本
CArrayCObArrayCPtrArray wxArray
CStringArray wxArrayString
CDWordArrayCByteArrayCUIntArray wxArrayInt
CListCPtrListCObList wxList
CStringList wxArrayStringwxStringList
CMap wxHashMap
CString wxString
CPoint wxPoint
CRect wxRect
CSize wxSize
CTime wxDateTime
CTimeSpan wxTimeSpanwxDateSpan
COleVariant wxVariant
Internet 类
MFC 版本 wxWidgets 版本
CSocket wxSocket
CFtpConnection wxFTP
CHttpConnection wxHTTP
文档/视图类
MFC 版本 wxWidgets 版本
CDocument wxDocument
CView wxView
CDocTemplateCSingleDocTemplateCMultiDocTemplate wxDocTemplate
拖放类
MFC 版本 wxWidgets 版本
COleDataSource wxDataObject
COleDropSource wxDropSource
COleDropTarget wxDropTarget
文件类
MFC 版本 wxWidgets 版本
CFile wxFilewxFFilewxTextFile
CMemFile wxMemoryInputStreamwxMemoryOutputStream
CSocketFile wxSocketInputStreamwxSocketOutputStream
CRecentFileList wxFileHistory
多线程类
MFC 版本 wxWidgets 版本
CWinThread wxThread
CCriticalSection wxCriticalSection
CMutex wxMutex
CSemaphore wxSemaphore

类层次结构

入门

开始使用 wxWidgets 真的非常容易。只需遵循以下步骤

  • 从 sourceforge.net 网站下载 wxMSW-2.6.2-Setup.exe
  • 运行安装程序 EXE 并将其安装到例如 "C:\wxWidgets\" 文件夹中。
  • 向您的系统添加环境变量 $(WXWIN)。该值将是您安装 wxWidgets 的文件夹路径。
    1. 右键单击桌面上的“我的电脑”图标。
    2. 选择“属性”。
    3. 出现一个对话框。在该对话框中选择“高级”选项卡。
    4. 单击“环境变量”按钮。
    5. 出现另一个对话框。在“系统变量”框中单击“新建”按钮。
    6. 在“变量名”文本框中添加“WXWIN”,在“变量值”文本框中添加您安装 wxWidgets 的文件夹路径。
    7. 单击“确定”按钮,直到所有对话框消失。

  • 在 Visual Studio 中打开 "src\wxWindows.dsw" 和 "build\msw\wx.dsw" 文件,并为所有项目配置构建解决方案中的项目(库),即:Debug、Release、Debug DLL、Release DLL、Unicode Debug、Unicode Release、Unicode Debug DLL、Unicode Release DLL。这些解决方案文件位于 wxWidgets 安装文件夹中。此步骤将创建我们的应用程序链接所需的一些库。这些文件将创建在您的 wxWidgets 安装目录下的 "lib"、"lib\vc_lib\" 和 "lib\vc_dll\" 文件夹中。
  • 现在一切都准备就绪,可以感受 wxWidgets 的强大功能了。

Hello world

Hello world 是学习任何新语言的经典示例。它概述了语言,而无需深入研究。

  • 只需在 Visual Studio 编辑器中创建类型为“Win32 项目”的新项目“HelloWorld”

  • 在“应用程序设置”中,将应用程序类型选择为“Windows 应用程序”,并在“附加选项”中勾选“空项目”复选框,然后单击“完成”按钮

  • 现在,通过按“Ctrl+N”创建新文件,并在“Visual C++”类别中选择类型为“C++ 文件”。单击“打开”

  • 现在将以下代码输入文件
    /*
     * hworld.cpp
     * Hello world sample by Robert Roebling
     */
     
    #include "wx/wx.h" 
     
    
    class MyApp: public wxApp
    {
        virtual bool OnInit();
    };
    
     
    class MyFrame: public wxFrame
    {
    public:
     
        MyFrame(const wxString& title, 
               const wxPoint& pos, const wxSize& size);
    
        void OnQuit(wxCommandEvent& event);
        void OnAbout(wxCommandEvent& event);
     
        DECLARE_EVENT_TABLE()
    };
    
    enum
    {
        ID_Quit = 1,
        ID_About,
    
    };
     
    BEGIN_EVENT_TABLE(MyFrame, wxFrame)
        EVT_MENU(ID_Quit, MyFrame::OnQuit)
        EVT_MENU(ID_About, MyFrame::OnAbout)
    END_EVENT_TABLE()
     
    IMPLEMENT_APP(MyApp)
    
    bool MyApp::OnInit()
    {
        MyFrame *frame = new MyFrame( "Hello World", 
             wxPoint(50,50), wxSize(450,340) );
        frame->Show(TRUE);
        SetTopWindow(frame);
        return TRUE;
    } 
     
    MyFrame::MyFrame(const wxString& title, 
           const wxPoint& pos, const wxSize& size)
    : wxFrame((wxFrame *)NULL, -1, title, pos, size)
    {
        wxMenu *menuFile = new wxMenu;
        menuFile->Append( ID_About, "&About..." );
        menuFile->AppendSeparator();
        menuFile->Append( ID_Quit, "E&xit" );
     
        wxMenuBar *menuBar = new wxMenuBar;
        menuBar->Append( menuFile, "&File" );
     
        SetMenuBar( menuBar );
    
        CreateStatusBar();
        SetStatusText( "Welcome to wxWindows!" );
    }
    
     
    void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
    {
        Close(TRUE);
    }
     
    void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
    {
    
        wxMessageBox("This is a wxWindows Hello world sample",
            "About Hello World", wxOK | wxICON_INFORMATION, this);
    }
  • 现在将文件保存到“HelloWorld”项目文件夹中,命名为 "Hello.cpp"

  • 现在,在“解决方案资源管理器”中右键单击“源文件”>>“添加”>>“添加现有项...”,将文件添加到项目中

  • 选择“打开”

  • 现在,从项目菜单中选择属性

  • 展开“C/C++”节点并选择“常规”。在“附加包含目录”中为“Debug”配置添加以下行
    "$(WXWIN)\include";"$(WXWIN)\contrib\include";"$(WXWIN)\lib\mswd"

    对于“Release”配置,添加以下行

    "$(WXWIN)\include";"$(WXWIN)\contrib\include";"$(WXWIN)\lib\msw"

  • 在“预处理器”选项卡中,为“Debug”配置在“预处理器定义”中添加以下行
    WIN32;_DEBUG;_WINDOWS;__WINDOWS__;__WXMSW__;__WXDEBUG__;WXDEBUG=1;
    __WIN95__;__WIN32__;WINVER=0x0400;STRICT

    对于“Release”配置,添加以下行

    NDEBUG,WIN32,_WINDOWS,__WINDOWS__,__WXMSW__,__WIN95__,__WIN32__, 
    WINVER=0x0400,STRICT

  • 在“代码生成”中,为“Debug”配置选择“运行时库”为
    Multi-threaded Debug DLL (/MDd)

    对于“Release”配置为

    Multi-threaded DLL (/MD)

  • 展开“链接器”节点并选择“常规”。在“附加库目录”中,为“Debug”配置添加以下行
    "$(WXWIN)\lib";"$(WXWIN)\contrib\lib";"$(WXWIN)\lib\vc_lib"

    对于“Release”配置,添加以下行

    "$(WXWIN)\lib";"$(WXWIN)\contrib\lib";"$(WXWIN)\lib\vc_lib"

  • 在“输入”选项卡中,为“Debug”配置在“附加依赖项”中添加以下行
    wxmsw26d_core.lib wxbase26d.lib wxtiffd.lib wxjpegd.lib 
    wxpngd.lib wxzlibd.lib wxregexd.lib wxexpatd.lib
    winmm.lib comctl32.lib rpcrt4.lib wsock32.lib oleacc.lib 
    kernel32.lib user32.lib gdi32.lib winspool.lib
    comdlg32.lib advapi32.lib shell32.lib ole32.lib 
    oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
  • 对于“Release”配置,添加以下行
    wxmsw26_core.lib wxbase26.lib wxtiff.lib wxjpeg.lib 
    wxpng.lib wxzlib.lib wxregex.lib wxexpat.lib 
    winmm.lib comctl32.lib rpcrt4.lib wsock32.lib oleacc.lib 
    odbc32.lib kernel32.lib user32.lib gdi32.lib
    winspool.lib comdlg32.lib advapi32.lib shell32.lib 
    ole32.lib oleaut32.lib uuid.lib odbccp32.lib

  • 按“确定”按钮保存这些更改,并从构建菜单中构建解决方案

  • 从“调试”菜单中选择“启动”或“不调试启动”以执行程序

恭喜!

您已成功使用 wxWidgets 创建您的第一个“Hello World”程序

Visual C++ 2005 Express

按照Express Edition 的手动安装说明中给出的说明安装 Visual C++ 2005 Express,然后按照将 Visual C++ 2005 Express Beta 2 与 Microsoft Platform SDK 结合使用中给出的步骤配置平台 SDK。之后,您需要更改以下内容

[编辑注释:使用换行符以避免滚动。]

%program Files%\Microsoft Visual Studio 8\VC\VCProjectDefaults\
                                         corewin_express.vsprops

将“_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE”设置为 PreprocessorDefinitions

一个示例 corewin_express.vsprops 文件

<?xml version="1.0" ?>
<VisualStudioPropertySheet ProjectType="Visual C++" 
   Version="8.00" Name="Core Windows Libraries">
    <Tool Name="VCLinkerTool" AdditionalDependencies=
        "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
        advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib" />
    <Tool Name="VCCLCompilerTool" PreprocessorDefinitions=
        "_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE" />
</VisualStudioPropertySheet>

然后打开文件 $(WXWIN)\src\msw\main.cpp,搜索函数 'DllMain' 并添加以下行

#if _MSC_VER >= 1400 && _WINDLL
#undef _WINDLL
#endif

在该行之前

#if defined(_WINDLL)

配置完 Visual Studio 后,其余步骤相同,只需遵循上面针对 Visual Studio .NET 给出的说明,并打开 wx.dsw 文件,然后为所有项目配置编译库,即:Debug、Release、Debug DLL、Release DLL、Unicode Debug、Unicode Release、Unicode Debug DLL、Unicode Release DLL。

VC8 还改变了清单嵌入到可执行文件中的方式。如果您将 wx.manifest 包含在资源文件中,您的项目将无法构建。首先,通过将定义语句添加到您的 YourAppName.rc 文件中,将清单从您的资源中排除

#define wxUSE_NO_MANIFEST 1

其次,将这些行添加到您的一个源文件或头文件中,以启用 XP 样式通用控件

#if defined(__WXMSW__) && !defined(__WXWINCE__)
#pragma comment(linker, "\"/manifestdependency:type='win32' 
    name='Microsoft.Windows.Common-Controls' version='6.0.0.0'
    processorArchitecture='X86' publicKeyToken='6595b64144ccf1df'\"")
#endif

Linux

由于图片数量众多和下载时间较长,本节已移至新文章。有关在 Linux 上使用 wxWidgets 的信息,请参见此处

理解程序

您当然必须包含 wxWidgets 的头文件。这可以逐个文件地完成(例如 #include "wx/window.h")或使用一个全局包含(#include "wx/wx.h")。这对于支持预编译头的平台(例如 Windows 平台上的所有主要编译器)也很有用

// file name: hworld.cpp
//
// purpose: wxWidgets "Hello world"
//

// For compilers that support precompilation,
// includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
  #pragma hdrstop
#endif

#ifndef WX_PRECOMP
 #include "wx/wx.h"
#endif

实际上,每个应用程序都应该定义一个派生自 wxApp 的新类。通过重写 wxAppOnInit(),可以初始化程序,例如通过创建一个新的主窗口。

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

主窗口是通过从 wxFrame 派生一个类并在其构造函数中为其提供菜单和状态栏来创建的。此外,任何希望响应任何“事件”(例如鼠标单击或来自菜单或按钮的消息)的类都必须使用以下宏声明一个事件表。最后,必须在“处理程序”中完成对这些事件的反应方式。在我们的示例中,我们响应两个菜单项,一个用于“退出”,一个用于显示“关于”窗口。这些处理程序不应该是 virtual

class MyFrame: public wxFrame
{
public:
  MyFrame(const wxString& title, const wxPoint& pos, 
                                  const wxSize& size);

  void OnQuit(wxCommandEvent& event);
  void OnAbout(wxCommandEvent& event);

private:
  DECLARE_EVENT_TABLE()
};

为了能够响应菜单命令,必须为其指定一个唯一的标识符,例如 constenum

enum
{
  ID_Quit = 1,
  ID_About,
};

然后我们继续实际实现一个事件表,其中事件被路由到 MyFrame 类中各自的处理函数。有预定义的宏用于路由所有常见事件,从列表框条目的选择到用户在屏幕上调整窗口大小时的调整大小事件。如果 ID 给定为 -1,则指定处理程序将为指定类型的任何事件调用,因此您只需在事件表中为所有菜单命令或所有按钮命令等添加一个条目。事件的来源仍可在事件处理程序中区分,因为事件处理程序中的(唯一)参数是对 wxEvent 对象的引用,该对象包含有关事件的信息(例如导致事件的类的 ID 和指针)。

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
  EVT_MENU(ID_Quit, MyFrame::OnQuit)
  EVT_MENU(ID_About, MyFrame::OnAbout)
END_EVENT_TABLE()

与所有程序一样,必须有一个“main”函数。在 wxWidgets 下,main 是使用此宏实现的,该宏创建应用程序实例并启动程序

IMPLEMENT_APP(MyApp)

如上所述,wxApp::OnInit() 在启动时调用,应该用于初始化程序,可能用于显示“启动画面”并创建主窗口(或多个)。帧应获取标题栏文本(“Hello World”)以及位置和启动大小。一个帧也可以声明为顶级窗口。返回 TRUE 表示初始化成功

bool MyApp::OnInit()
{
  MyFrame *frame = new MyFrame( "Hello World", 
                    wxPoint(50,50), wxSize(450,340) );
  frame->Show( TRUE );
  SetTopWindow( frame );
  return TRUE;
}

在主窗口的构造函数中(或稍后),我们创建了一个带有两个菜单项的菜单以及一个状态栏,以显示在主窗口的底部。两者都必须通过各自的调用“通知”帧

MyFrame::MyFrame(const wxString& title, 
          const wxPoint& pos, const wxSize& size)
 : wxFrame((wxFrame *)NULL, -1, title, pos, size)
{
  wxMenu *menuFile = new wxMenu;

  menuFile->Append( ID_About, "&About..." );
  menuFile->AppendSeparator();
  menuFile->Append( ID_Quit, "E&xit" );

  wxMenuBar *menuBar = new wxMenuBar;
  menuBar->Append( menuFile, "&File" );

  SetMenuBar( menuBar );

  CreateStatusBar();
  SetStatusText( "Welcome to wxWidgets!" );
}

这是实际的事件处理程序。MyFrame::OnQuit() 通过调用 Close() 关闭主窗口。参数 TRUE 表示其他窗口没有否决权,例如在询问“您真的要关闭吗?”之后。如果没有其他主窗口,应用程序将退出

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
  Close( TRUE );
}

MyFrame::OnAbout() 将显示一个小窗口,即带有文本的消息框。在这种情况下,是典型的“关于”窗口,其中包含有关程序的信息

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
  wxMessageBox( "This is a wxWidgets's Hello world sample", 
    "About Hello World", wxOK | wxICON_INFORMATION );
}

事件如何处理

事件表放置在实现文件中,以告诉 wxWindows 如何将事件映射到成员函数。这些成员函数不是 virtual 函数,但它们的形式都相似:它们接受一个 wxEvent 派生参数,并且具有 void 返回类型。

这是一个事件表的示例

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
  EVT_MENU    (wxID_EXIT, MyFrame::OnExit)
  EVT_MENU    (DO_TEST,   MyFrame::DoTest)
  EVT_SIZE    (           MyFrame::OnSize)
  EVT_BUTTON  (BUTTON1,   MyFrame::OnButton1)
END_EVENT_TABLE()

前两个条目将菜单命令映射到两个不同的成员函数。EVT_SIZE 宏不需要窗口标识符,因为通常您只对当前窗口的大小事件感兴趣。(实际上,您可以通过使用 EVT_CUSTOM(wxEVT_SIZE, ID, func) 来拦截特定窗口的大小事件。)

EVT_BUTTON 宏演示了原始事件不必来自实现事件表的窗口类 - 如果事件源是面板内框架内的按钮,这仍然有效,因为事件表会向上搜索窗口层次结构。在这种情况下,将搜索按钮的事件表,然后是父面板的,然后是框架的。

如前所述,处理事件的成员函数不必是 virtual。事实上,成员函数不应该是 virtual 的,因为事件处理程序会忽略这些函数是 virtual 的,即在派生类中重写 virtual 成员函数将没有任何效果。这些成员函数接受一个事件参数,事件的类根据事件的类型和原始窗口的类而不同。对于大小事件,使用 wxSizeEvent。对于菜单命令和大多数控件命令(例如按钮按下),使用 wxCommandEvent。当控件变得更复杂时,将使用特定的事件类,例如 wxTreeEvent 用于来自 wxTreeCtrl 窗口的事件。

实现文件中的事件表必须在类定义中包含 DECLARE_EVENT_TABLE 宏。例如

class MyFrame: public wxFrame {

  DECLARE_DYNAMIC_CLASS(MyFrame)

public:
  ...
  void OnExit(wxCommandEvent& event);
  void OnSize(wxSizeEvent& event);
protected:
  int       m_count;
  ...
  DECLARE_EVENT_TABLE()
};

当从窗口系统收到事件时,wxWindows 会在生成事件的窗口所属的第一个事件处理程序对象上调用 wxEvtHandler::ProcessEvent

需要注意的是,wxWindows 的事件处理系统实现了与普通 C++ 中的 virtual 方法非常相似的东西,即可以通过重写其事件处理函数来改变类的行为。在许多情况下,这甚至适用于改变原生控件的行为。例如,可以通过重写 wxTextCtrl 并使用 EVT_KEY_DOWN 定义键盘事件处理程序来过滤掉系统发送给原生文本控件的一些键盘事件。这确实会阻止任何键盘事件发送到原生控件 - 这可能不是所希望的。在这种情况下,事件处理函数必须调用 Skip() 以指示应继续搜索事件处理程序。

总而言之,您不应该像使用 C++ virtual 函数那样显式调用基类版本(即 wxTextCtrl::OnChar()),而应该调用 Skip

实际上,如果派生文本控件只接受“a”到“z”和“A”到“Z”,它将如下所示

void MyTextCtrl::OnChar(wxKeyEvent& event)
{
    if ( isalpha( event.KeyCode() ) )
    {
       // key code is within legal range. we call event.Skip() so the
       // event can be processed either in the base wxWindows class
       // or the native control.

       event.Skip();
    }
    else
    {
       // illegal key hit. we don't call event.Skip() so the
       // event is not processed anywhere else.

       wxBell();
    }
}

ProcessEvent 的事件表搜索的正常顺序如下

  1. 如果对象被禁用(通过调用 wxEvtHandler::SetEvtHandlerEnabled),则函数跳到步骤 (6)。
  2. 如果对象是 wxWindow,则 ProcessEvent 会递归调用窗口的 wxValidator。如果这返回 TRUE,则函数退出。
  3. 为该事件处理程序调用 SearchEventTable。如果失败,则尝试基类表,依此类推,直到没有更多表或找到适当的函数,在这种情况下函数退出。
  4. 搜索应用于整个事件处理程序链(通常链的长度为一)。如果成功,函数退出。
  5. 如果对象是 wxWindow 且事件是 wxCommandEvent,则 ProcessEvent 会递归应用于父窗口的事件处理程序。如果这返回 TRUE,则函数退出。
  6. 最后,在 wxApp 对象上调用 ProcessEvent

请密切关注第 5 步:人们经常忽略或混淆 wxWindows 事件处理系统的强大功能。换句话说,直接或间接派生自 wxCommandEvent 的事件将沿包含层次结构从子级向父级传播,直到找到不调用 event.Skip() 的事件处理程序。不派生自 wxCommandEvent 的事件会发送到它们发生的窗口,然后停止。

最后,还有另一个额外的复杂性(这实际上大大简化了 wxWindows 程序员的生活):当命令事件向上传播到父窗口时,如果事件到达父对话框,事件传播就会停止。这意味着您不会在弹出模态对话框时面临从对话框控件(可能由于对话框本身不关心而未处理)接收到意外事件的风险。然而,事件会传播到框架之外。这种选择的理由是,典型的应用程序中只有少数框架,程序员对它们的父子关系非常清楚,而追踪复杂程序中可能弹出的所有对话框(请记住有些是由 wxWindows 自动创建的)可能非常困难,甚至不可能。如果您由于某种原因需要指定不同的行为,可以显式使用 SetExtraStyle(wxWS_EX_BLOCK_EVENTS) 来阻止事件传播到给定窗口之外,或者对于默认情况下具有此标志的对话框取消设置此标志。

通常,处理窗口作为窗口的事件(大小、移动、绘制、鼠标、键盘等)只会发送到窗口。具有更高含义和/或由窗口本身生成的事件(按钮单击、菜单选择、树展开等)是命令事件,并发送到父级以查看它是否对该事件感兴趣。

请注意,您的应用程序可能希望重写 ProcessEvent 以重定向事件的处理。例如,在文档/视图框架中,这样做是为了允许在文档或视图中定义事件处理程序。为了测试命令事件(可能这是您唯一希望重定向的事件),您可以高效地使用 wxEvent::IsCommandEvent,而不是使用较慢的运行时类型系统。

如上所述,只有命令事件会递归应用于父级的事件处理程序。由于这经常导致用户混淆,以下是发送到父级事件处理程序的系统事件列表

wxEvent 事件基类。
wxActivateEvent 窗口或应用程序激活事件。
wxCloseEvent 关闭窗口或结束会话事件。
wxEraseEvent 擦除背景事件。
wxFocusEvent 窗口焦点事件。
wxKeyEvent 按键事件。
wxIdleEvent 空闲事件。
wxInitDialogEvent 对话框初始化事件。
wxJoystickEvent 操纵杆事件。
wxMenuEvent 菜单事件。
wxMouseEvent 鼠标事件。
wxMoveEvent 移动事件。
wxPaintEvent 绘制事件。
wxQueryLayoutInfoEvent 用于查询布局信息。
wxSizeEvent 大小事件。
wxScrollWinEvent 由滚动窗口(不是滚动条)发送的滚动事件。
wxSysColourChangedEvent 系统颜色更改事件。
wxUpdateUIEvent 用户界面更新事件。

在某些情况下,程序员可能希望在父窗口中获取一定数量的系统事件,例如,所有发送到但未被对话框中的原生控件使用的按键事件。在这种情况下,必须编写一个特殊的事件处理程序,它将重写 ProcessEvent() 以便将所有事件(或其中的任何选择)传递给父窗口。

其他要点

  • 您可以创建一个类似于 MFC 中 "stdafx.h" 的 "stdwx.h" 文件作为预编译头。在项目设置中,在“C/C++”选项卡中的“预编译头”下,为“创建/使用预编译头”选择“自动生成 (/YX)”,为“通过文件创建/使用 PCH”选择 "stdwx.h"。 "stdwx.h" 文件的内容如下
    #ifndef _stdwx_h_
    #define _stdwx_h_
    
    // SYSTEM INCLUDES
    #include <wx/wxprec.h>
    #ifdef __BORLANDC__
        #pragma hdrstop
    #endif
    #ifndef WX_PRECOMP
        #include "wx/wx.h"
    #endif
    
    // APPLICATION INCLUDES
    #endif
  • 此外,对于“资源”选项卡中“常规”下的“附加包含目录”,调试和发布配置使用
    "$(WXWIN)\include";
  • wxWidgets 安装中的 "setup.h" 文件有许多开关。这些开关可用于启用/禁用对 ODBC、STL 等功能的支持,并且只会编译您将使用的那些类。它们是简单的 define 语句,其值可以更改为 1 表示启用,0 表示禁用。

关于 EyeCare

Eye Care 基本上受到 Alok Gupta 应用程序的启发。它是一个小型实用程序,当您沉浸在编程的矩阵中时,它会提醒您在预设时间间隔后让眼睛休息并清洗它们。它位于任务栏中,并监控您的眼睛。完全用 wxWidgets 编写,它是 wxWidgets 编程有多么容易的另一个例子。它还展示了如何在任务栏中放置应用程序图标、保存应用程序配置、使用图像、处理窗口特定消息、使用 wxCode 组件(如 wxHyperlinkCtrl)以及其他概念。

wxVisualIntergration 和 wxVCExpressIntegration

由 Priyank Bolia 编写的 wxVisualIntergration 和 wxVCExpressIntegration 通过提供各种向导,集成了对 Visual Studio .NET 2003 和 Visual C++ 2005 Express 的 wxWidgets 支持。 wxVisualIntergration 可从此处下载,wxVCExpressIntegration 可从此处下载。

特点

  • 为 Windows、控制台和基于 DLL 的应用程序提供项目向导。
  • 所有类型的项目设置,如启用 Unicode、静态/动态链接,只需点击几下鼠标即可完成。
  • 可选择的附加属性,如:单实例、WinXP 主题、wxFormBuilder 支持。
  • 节省大量宝贵时间,并减少手动设置造成的错误。
  • 项目具有调试内存管理、预编译头、默认菜单、工具栏、状态栏等。

有用网站

一些使用 wxWidgets 的流行应用程序

结论

wxWidgets 许可证本质上是 L-GPL(库通用公共许可证),但有一个例外,即二进制形式的衍生作品可以根据用户自己的条款分发。这个解决方案既满足了希望使用 wxWidgets 制作 GPL 软件的人,也满足了制作专有软件的人。正如您所看到的,在不断增长的 Linux 和 MAC 世界中,wxWidgets 是 Windows 程序员学习最快、最易用且最佳的解决方案(无版税,无专利)。

© . All rights reserved.