wxWidgets 简介






4.55/5 (119投票s)
wxWidgets 跨平台 GUI 开发初学者教程。
- 下载 hello world 演示项目 - 329 Kb
- 下载 hello world 演示项目(备用链接)
- 下载 eye care 演示项目 - 387 Kb
- 下载 eye care 演示项目(备用链接)
引言
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 不使用任何中间层,并且只使用平台上可用的原生控件,因此它为应用程序提供了美观的外观和感觉。
- 它非常完整。有许多实用程序类,例如:
wxRegEx
、wxFTP
、wxSplashScreen
、wxZipInputStream
等。 - 它仍在大力开发中,并得到了开源社区的大力支持。
- 支持许多编译器和平台:Windows、Linux、Mac、Unix。
- 互联网上、论坛、wxBook 上有很多可用文档。
- 它免费用于个人和商业用途,并且比 LGPL 许可更灵活。
- 只要可能,wxWindows 会使用平台 SDK。这意味着在 Windows 上编译的程序将具有 Windows 程序的外观和感觉,而在 Linux 机器上编译时,它将具有 Linux 程序的外观和感觉。
- 易学,它具有与 WINAPI 和 MFC 相同的事件表和相似的 API 和类。
- 安装的 samples 目录中提供了许多示例,其中包含如何使用基本控件、多线程、MDI、拖放、套接字、打印等等。
- 有许多现成的类可用,例如:
wxGenericDirCtrl
、wxCalendarCtrl
、wxDatePickerCtrl
、wxTipWindow
、wxStyledTextCtrl
、wxStaticPicture
、wxLEDNumberCtrl
、wxEditableListBox
、wxFoldPanelBar
、wxGIFAnimationCtrl
、wxSplashScreen
、OGL
(对象图形库)、FL
(帧布局)等。这是主要的存储库之一。 - 有许多附加库可用于使编程任务更容易
- wxMozilla.
- wxIndustrialControls.
- wxCURL.
- ToasterBox.
- wxVTK.
- wxDockIt.
- wxIFM.
- wxMathPlot.
- wxTreeMultiCtrl.
- wxAUI.
- wxPropertyGrid.
- wxSMTP.
- wxResizeableControl.
- wxOTL.
- wxReportWriter.
- wxHyperlinkCtrl.
- wxSQLite.
- wxIE.
- wxCTB.
- AWX.
- wxSpellChecker.
- wxArt2D.
- wxImprola.
- wxHTML.
- wxStEdit.
- wxLCDWindow.
- mmwx.
- LitWindow.
- Keybinder.
- wxBetterDialog.
- wxBZipStream.
- wxCrashReport.
- wxHTTPServer.
- wxRarInputStream.
- wxSheet.
- wxStreamMerger.
主要功能
- 多线程。
- 剪贴板和拖放。
- 网络编程,例如:
wxSMTP
、wxHTTP
、wxFTP
。 - 各种流行格式的图像加载和保存。
- 流(ZIP、网络、文件等),例如:
wxRarInputStream
。 - 数据库支持,例如:
wxDao
。 - HTML 查看和打印,例如:
wxMozilla
、wxIE
。 - 基于 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 |
wxMenu、wMenuBar、wxMenuItem |
CWaitCursor |
wxBusyCursor |
CDataExchange |
wxValidator |
窗口类 | |
MFC 版本 | wxWidgets 版本 |
CFrameWnd |
wxFrame |
CMDIFrameWnd |
wxMDIParentFrame |
CMDIChildWnd |
wxMDIChildFrame |
CSplitterWnd |
wxSplitterWindow |
CToolBar |
wxToolBar |
CStatusBar |
wxStatusBar |
CReBar |
wxCoolBar,但请参阅 contrib/src/fl 和 wxAUI、wxDockIt |
CPropertyPage |
wxPanel |
CPropertySheet |
wxNotebook、wxPropertySheetDialog |
对话框类 | |
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 |
wxComboBox、wxChoice |
CDateTimeCtrl |
wxDatePickerCtrl |
CEdit |
wxTextCtrl |
CHotKeyCtrl |
无,但请参阅 Keybinder |
CListBox 、CDragListBox |
wxListBox |
CCheckListBox |
wxCheckListBox |
CListCtrl |
wxListCtrl、wxListView |
CMonthCalCtrl |
wxCalendarCtrl |
CProgressCtrl |
wxGauge |
CReBarCtrl |
无,但请参阅 contrib/src/fl 和 wxAUI、wxDockIt |
CRichEditCtrl |
wxTextCtrl |
CScrollBar |
wxScrollBar |
CSliderCtrl |
wxSlider |
CSpinButtonCtrl |
wxSpinButton、wxSpinCtrl |
CStatic |
wxStaticText、wxStaticLine、wxStaticBox、wxStaticBitmap |
CStatusBarCtrl |
wxStatusBar |
CTabCtrl |
wxTabCtrl |
CToolBarCtrl |
wxToolBar |
CToolTipCtrl |
wxToolTip |
CTreeCtrl |
wxTreeCtrl |
图形类 | |
MFC 版本 | wxWidgets 版本 |
CBitmap |
wxBitmap、wxImage、wxIcon、wxCursor |
CBrush |
wxBrush |
CPen |
wxPen |
CFont |
wxFont |
CImageList |
wxImageList、wxIconBundle |
CPalette |
wxPalette |
CRgn |
wxRegion |
CClientDC |
wxClientDC |
CMetaFileDC |
wxMetaFileDC |
CPaintDC |
wxPaintDC |
CWindowDC |
wxWindowDC |
CDC |
wxDC、wxMemoryDC |
数据结构类 | |
MFC 版本 | wxWidgets 版本 |
CArray 、CObArray 、CPtrArray |
wxArray |
CStringArray |
wxArrayString |
CDWordArray 、CByteArray 、CUIntArray |
wxArrayInt |
CList 、CPtrList 、CObList |
wxList |
CStringList |
wxArrayString、wxStringList |
CMap |
wxHashMap |
CString |
wxString |
CPoint |
wxPoint |
CRect |
wxRect |
CSize |
wxSize |
CTime |
wxDateTime |
CTimeSpan |
wxTimeSpan、wxDateSpan |
COleVariant |
wxVariant |
Internet 类 | |
MFC 版本 | wxWidgets 版本 |
CSocket |
wxSocket |
CFtpConnection |
wxFTP |
CHttpConnection |
wxHTTP |
文档/视图类 | |
MFC 版本 | wxWidgets 版本 |
CDocument |
wxDocument |
CView |
wxView |
CDocTemplate 、CSingleDocTemplate 、CMultiDocTemplate |
wxDocTemplate |
拖放类 | |
MFC 版本 | wxWidgets 版本 |
COleDataSource |
wxDataObject |
COleDropSource |
wxDropSource |
COleDropTarget |
wxDropTarget |
文件类 | |
MFC 版本 | wxWidgets 版本 |
CFile |
wxFile、wxFFile、wxTextFile |
CMemFile |
wxMemoryInputStream、wxMemoryOutputStream |
CSocketFile |
wxSocketInputStream、wxSocketOutputStream |
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 的文件夹路径。
- 右键单击桌面上的“我的电脑”图标。
- 选择“属性”。
- 出现一个对话框。在该对话框中选择“高级”选项卡。
- 单击“环境变量”按钮。
- 出现另一个对话框。在“系统变量”框中单击“新建”按钮。
- 在“变量名”文本框中添加“WXWIN”,在“变量值”文本框中添加您安装 wxWidgets 的文件夹路径。
- 单击“确定”按钮,直到所有对话框消失。
- 在 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
的新类。通过重写 wxApp
的 OnInit()
,可以初始化程序,例如通过创建一个新的主窗口。
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() };
为了能够响应菜单命令,必须为其指定一个唯一的标识符,例如 const
或 enum
。
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
的事件表搜索的正常顺序如下
- 如果对象被禁用(通过调用 wxEvtHandler::SetEvtHandlerEnabled),则函数跳到步骤 (6)。
- 如果对象是
wxWindow
,则ProcessEvent
会递归调用窗口的 wxValidator。如果这返回TRUE
,则函数退出。 - 为该事件处理程序调用
SearchEventTable
。如果失败,则尝试基类表,依此类推,直到没有更多表或找到适当的函数,在这种情况下函数退出。 - 搜索应用于整个事件处理程序链(通常链的长度为一)。如果成功,函数退出。
- 如果对象是
wxWindow
且事件是wxCommandEvent
,则ProcessEvent
会递归应用于父窗口的事件处理程序。如果这返回TRUE
,则函数退出。 - 最后,在
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 主页.
- wxCode 存储库.
- wx教程.
- 使用 wxWidgets 在 C++ 中绘图和打印.
- wxWidgets 与 Visual Studio.NET 的帮助集成.
- wxGlade Flash 演示.
- wxWidgets 论坛.
- wxBook 项目.
- 将 Windows MFC 应用程序移植到 Linux.
一些使用 wxWidgets 的流行应用程序
- AOL Communicator
- FileZilla
- poedit
- Audacity
- AVG AntiVirus
- CADToMill
- Chandler
- Chess Commander
- CTSim
- Display Doctor
- EarthVision
- Forte Agent
- HelpBlocks
- ImageLinks
- Kirix Strata
- Intuitive MX
- iPodder
- LDAP Explorer
- ShareDaemon
- Mahogany
- MinGW Developer Studio
- MojoWorld
- Musik
- StoryLines
- TerraIM
- TortoiseCVS
- VietAnh
- Voxel 3D
- Vulcan
- wxBlogger
- xCHM
- Zeemo
- Zempt 和更多 应用程序 / 用户
结论
wxWidgets 许可证本质上是 L-GPL(库通用公共许可证),但有一个例外,即二进制形式的衍生作品可以根据用户自己的条款分发。这个解决方案既满足了希望使用 wxWidgets 制作 GPL 软件的人,也满足了制作专有软件的人。正如您所看到的,在不断增长的 Linux 和 MAC 世界中,wxWidgets 是 Windows 程序员学习最快、最易用且最佳的解决方案(无版税,无专利)。