// * create by zyzx
// * 2009-3-16
// * 转载请注明来源:http://www.cppblog.com/zyzx
想了几天,不知道如何动笔写例程,网络上关于wx框架例程也不多。入门最好先读《Cross-Platform GUI Programming with wxWidgets_CN》(中文版)和wx库本身自带的说明文档。
关于组件的使用,官方源代码中提供了很多例程wxWidgets-2.8.7\samples。
回想我作为初学者时,或许走了一些弯路。刚开始当然是读教程和官方说明文档,再到手工编写UI组件(熟悉基本的几个,其他的在使用上是差不多的),最后是结合工具DialogBlocks编写。wx库本身还有很多值得挖掘的地方,比如其事件绑定方式、XRC界面配置文件、SIZER界面自动配置、还有国际化等等。
这里我就按手工编写和借助工具分别写一份例程,例程的编写过程,就是熟悉库本身过程。
第一份手工编写的例程,我还是想借助于经典游戏《贪吃蛇》来实现。而第二份使用DialogBlocks来实现类似VS界面。
以前学习OpenGL时候,有经典的书在手,但总是没有程序实践感观,因而觉得很空洞。但自从慢慢的研读hehe关于OpenGL的系列的实例教程,再结合书籍才慢慢了解3D编程。况且,本人也对wx库了解不是很全面,也只能从其局部应用出发。因此,本系列例程程序侧重于代码实现,在很多方面还有局限性。关于wx库完整的结构还得参考其自带的说明文档。
第一例程简短的程序分四个文件:SnakeApp.h、SnakeApp.cpp、SnakeFrame.h、SnakeFrame.cpp。本系列例程会在此基础之上完成。
SnakeApp类中定义应用程序启动类,继承于wxApp。
SnakeFrame类定义主Frame,创建界面框架和其中的子窗口组件。
一、类SnakeApp头文件定义:
1
class
SnakeApp:
public
wxApp
2
{
3
public
:
4
//
* 定义动态创建类
5
DECLARE_CLASS( SnakeApp )
6
//
* 定义事件处理宏
7
DECLARE_EVENT_TABLE()
8
9
public
:
10
SnakeApp();
11
12
//
* 类初始化
13
void
Init();
14
//
* 窗口初始化
15
virtual
bool
OnInit();
16
//
* 退出
17
virtual
int
OnExit();
18
19
public
:
20
//
* 获取主Frame
21
SnakeFrame
*
GetMainFrame()
{
return
m_MainFrame; }
22
23
protected
:
24
SnakeFrame
*
m_MainFrame;
25
}
;
26
27
//
* 定义全局wxGetApp(),返回&SnakeApp
28
//
* 可以在工程的任意地方使用。
29
DECLARE_APP(SnakeApp)
wxApp是基于线程类有关的,一般应用程序将一个继承wxApp的类作为入口类,再用IMPLEMENT_APP宏定义入口类(入口地址)。
DECLARE_EVENT_TABLE宏静态定义此类接收的事件处理,未编写的事件按默认处理。
OnInit中一般是程序运行之前的创建窗口、配置程序环境等操作。
OnExit程序结束时,需要处理的操作。注意,wx库正常窗口链,在默认的wxApp::OnExit()函数执行后,都会被自动析构掉,并不需要显示的调用析构。如果正常的窗口链被破坏,需要做相应的特殊处理,比如混合使用MFC或WIN32的API,都有可能破坏正常的窗口链。
DECLARE_APP宏定义本工程中可以使用到的全局函数wxGetApp(),返回为本类的引用。此全局函数即为沟通其他各个部分(比如主Frame->窗口->组件)的中间桥梁。
二、类SnakeApp实现文件:
1
//
* 入口函数定义
2
IMPLEMENT_APP( SnakeApp )
3
4
//
* 动态创建类
5
IMPLEMENT_CLASS( SnakeApp, wxApp )
6
7
//
* 挂接事件响应宏
8
BEGIN_EVENT_TABLE( SnakeApp, wxApp )
9
END_EVENT_TABLE()
10
11
SnakeApp::SnakeApp()
12
{
13
Init();
14
}
15
16
void
SnakeApp::Init()
17
{
18
m_MainFrame
=
NULL;
19
}
20
21
bool
SnakeApp::OnInit()
22
{
23
//
* 加载能处理图片类型驱动
24
#if
wxUSE_XPM
25
wxImage::AddHandler(
new
wxXPMHandler);
26
#endif
27
#if
wxUSE_LIBPNG
28
wxImage::AddHandler(
new
wxPNGHandler);
29
#endif
30
#if
wxUSE_LIBJPEG
31
wxImage::AddHandler(
new
wxJPEGHandler);
32
#endif
33
#if
wxUSE_GIF
34
wxImage::AddHandler(
new
wxGIFHandler);
35
#endif
36
37
//
* 创建主Frame
38
SnakeFrame
*
mainWindow
=
new
SnakeFrame( NULL );
39
SetTopWindow( mainWindow );
40
mainWindow
->
Show(
true
);
41
42
m_MainFrame
=
mainWindow;
43
return
true
;
44
}
45
46
int
SnakeApp::OnExit()
47
{
48
return
wxApp::OnExit();
49
}
IMPLEMENT_CLASS宏回应头文件中的宏定义DECLARE_CLASS。
BEGIN_EVENT_TABLE、BEGIN_EVENT_TABLE:挂接事件宏。类似MFC中消息部分的处理。
DECLARE_CLASS宏表示此类可以被动态创建,指可以在运行时创建。实质是使用wxClassInfo来标记工程中唯一的类,运行时可以使用wxClassInfo信息来创建该类。Wx库中比较经典的应用是xrc文件中定义了一些窗口信息的文本标签,而程序运行时根据这些信息创建出一系列的窗口。如果窗口类需要运行时创建,必须要使用DECLARE_CLASS宏。注意本工程只是定义了此宏,并没有使用其动态创建特性。
wxImage::AddHandler()函数给wxImage的全局静态变量添加对应图片处理格式的Handler。责任链模式在wx库中有广泛的使用,作为使用者只需要关注wxImage提供的方法,而图片格式(*.jpg、*.png、*.gif等)由对应的Handler来处理。另一个使用比较经典的是窗口事件的分发。
New SnakeFrame( NULL ) 以NULL 为父窗指针的类一般直接或间接继承于wxTopLevelWindow,表示可以作为顶层窗口的类。
SetTopWindow( mainWindow )设置顶层窗口。
三、SnakeFrame类头文件
class
SnakeFrame:
public
wxFrame
{
public
:
DECLARE_CLASS( SnakeFrame )
DECLARE_EVENT_TABLE()
public
:
SnakeFrame(wxWindow
*
parent);
virtual
~
SnakeFrame();
//
* 初始化类
void
Init();
//
* 创建窗口框架组件
void
CreateControls();
protected
:
protected
:
//
* 窗口分割条
wxSplitterWindow
*
m_SplitterWindow;
}
;
如上部分UI View 部分即我们Demo需要完成的界面样子。
CreateControls()函数中中创建主Frame中的子窗口。
m_SplitterWindow本界面使用窗口分割条的方式将窗口分割成游戏区域和控制提示区域。
四、SnakeFrame类实现文件部分
IMPLEMENT_CLASS( SnakeFrame, wxFrame )
BEGIN_EVENT_TABLE( SnakeFrame, wxFrame )
END_EVENT_TABLE()
SnakeFrame::SnakeFrame(wxWindow
*
parent)
{
//
* 初始化类,并使用基类wxFrame创建Frame,其参数详细见wx文档
Init();
wxFrame::Create( parent, SNAKEFRAME_ID, SNAKEFRAME_TITLE, SNAKEFRAME_POSITION, SNAKEFRAME_SIZE, SNAKEFRAME_STYLE );
CreateControls();
Centre();
}
SnakeFrame::
~
SnakeFrame()
{
}
void
SnakeFrame::Init()
{
m_SplitterWindow
=
NULL;
}
void
SnakeFrame::CreateControls()
{
SnakeFrame
*
frame
=
this
;
//
* 创建窗口分割条
//
* wxID_ANY = -1,表示此窗口不能通过其ID来查询
wxSplitterWindow
*
splitterwnd
=
new
wxSplitterWindow( frame , wxID_ANY,SNAKEFRAME_POSITION, SNAKEFRAME_SIZE);
//
* 创建一个普通窗口
wxWindow
*
wnd1
=
new
wxWindow( splitterwnd , wxID_ANY);
//
* 创建一个文本编辑窗口
wxWindow
*
wnd2
=
new
wxTextCtrl( splitterwnd , wxID_ANY);
//
* 使用垂直分割方式,分成左右窗口
splitterwnd
->
SplitVertically( wnd1, wnd2, SNAKEFRAME_SPL );
//
* 设置分隔条SashSize为0,可以阻止拖动分割条改变窗口大小
splitterwnd
->
SetSashSize(
0
);
m_SplitterWindow
=
splitterwnd;
}
wxFrame::Create创建Frame窗口。Wx库中界面窗口部分类都有两种创建方式:一、直接使用构造函数直接创建;二、分两步,第一步使用默认构造函数只初始化类,第二步才使用Create函数来创建窗口。
wxSplitterWindow这里使用其将窗口分割成左右两部分,并设定分割条大小为0,即防止用户拖动分割条。这里暂时使用两个标准窗口来代替,下一个章节将替换这里为我们自己的类。
五、编译并执行
设置编译环境并编译得到如下界面。
如果有些部分没有提到,那是前面章节有可能已经提到,请翻阅前面部分查询。本系列从wx库的编译、配置、到demo的各个部分完成有比较强的依赖次序。
工程文件下载