wx网罗系列之入门: 使用wxWidgets编程——第一步

这是我非常喜欢的一个入门教程。我喜欢从这里出发。排版整理完毕。

 

 

译者注:出于个人对wxWindgets的爱好,翻译了此文,总共计8章。在翻译过程中,力求忠实于原文的表达方法。说真的中西方的表达方式真的有很大不同,单独看一个句子是没错误,可放联系上下文,就根本不是那么回事,所以想在两者之间找到一个平衡点,还真是件难事。不管各位怎么看,我还是会按自己的想法翻译下去,希望大家还能够看懂。


介绍

我们现在看到的是另外一种更为友好的建立winodws程序的方式,使用的是一套称着wxWidgets的类库。 严格地说wxWidgets不仅仅是一个库集,它还是一个应用程序框架,这也就意味着它提供有一个的体系结构,使之可以使用这些类来开发完整的应用程序。 使用wxWidgets的好处并没有就此停住,它也是一个跨平台的库。 引用wxWidgets作者的话:

wxWidgets是什么?
wxWidgets提供了简单易用的API,让你在多平台上编写GUI应用程序。 使用相应的针对你的平台(Windows/Unix/Mac)的库和编译器(几乎所有流行的C++编译器)进行连接(link),你的应用程序会采用与那个平台相对应的外观。 在强大的GUI功能方面,wxWidgets提供有: 在线帮助、网络编程、流、剪贴板拖拉、多线程、各种流行格式图像的装载和保存、数据库支持、HTML浏览和打印等许许多多的内容。

wxWidgets拥有很高的品质,实际上,有人可能会使用“商业品质”这个词汇来形容wxWidgets——意思是说它真的很好,值得付账。 这点千真万确,只是如果对于wxWidgets有批评的话,那就是,对于初学者,想要掌握它太难了: 刚开始的学习过程是有点复杂。 对于这个批评的乐观回复是一旦程序员掌握了wxWidgets的结构体系,例如它的类、函数和技巧,编写可用的应用程序将是一个非常有益和相对简单的过程 也可能有经济上的回报,wxWidgets是一个相当丰富的框架,以至几乎可以涉足什么应用程序领域。

在阅读本文时,你可能已经猜到我是一名狂热的wxWidgets支持者。 这是真的,我也很乐意通过这些网页将我对wxWinodws的热情传送给你。

我的计划是解释wxWidgets的体系结构以及通过一系列的例程,从最基础的开始介绍wxWidgets里的类。 在你完成之后,你应该可以很好地掌握wxWidgets了。

在开始之前,请注意以下几点:

  • 我并不认为我是个很不错的程序员,我也不认为我对wxWidgets有多精通,但我善于文字,我自信能够将复杂的问题解释清楚。
  • 你需要了解C和C++,但不定很详细。 在你学习wxWidgets的时个,你在C和C++方面的能力会大大增强。 如果你已经看了本网站的上大部分的C++资料,并且理解了,那我就认为你不会有什么问题。
  • 你需要理解面向对象编程和类。 在本站里的大部分资料将再一次有助于你。
  • 刚开始是在Windows平台上完成的。Win95, Win98 和 Win2K 全都用到了。 随同wxWidgets包一起的MingW提供的是开发环境。

如果你对C++编程还是个初学者,而你又想快速地进入使用wxWidgets开发“真实世界(real-world)”的GUI程序的殿堂,这几页将对你有很大的帮助。 跟着来吧!


wxWidgets体系结构和第一个程序

这只是个开始,而且我在一开始我就已经做了简化。 wxWidgets框架的第一个体系结构就是保持最简单的观点。 随着我们的深入,关于该框架我们会了解更多。

wxWidgets GUI程序的组成:

  • 一个应用程序对象——wxApp类的一个实例
  • 一个框架对象——wxFrame类的一个实例 一个框架(frame)可以有象菜单栏(menubar)、状态栏(statusbar)、图标(icon)等等内容。
  • 框架(frame)就是个容器,可以容纳许多其它象文本控制器(text control)、按钮(button)、分割器( splitter)等一样的对象。

在最简单的程序里,我们可能只有一个空的构架(frame),而且这个也是我们看到的第一个基本例子。 让人迷惘它到底有什么用是情有可原的。 如果没有其它的内容,它很更有指导意义,那也是我们首先看它的原因。 你会看到它显示出了windows应用程序所有的常见行为。 它有一个系统菜单,可以到处移动,可以改变大小并且可以关闭。


我知道它看起来并不怎么样,可它是我们的! 它也显示给我们这个程序展示的是本地GUI的外观。 这里是Windows 98,但是要记住wxWidgets是一个跨平台的框架而且可以用来为其它平台(象Linux,OS2,Mac等等)开发应用程序。

第一个例子的源代码显示如下:



 #ifndef BASIC_H
#define BASIC_H
class BasicApplication : public wxApp
{
public:
virtual bool OnInit();
};
 class BasicFrame : public wxFrame
{
public:
BasicFrame( const wxChar *title, int xpos, int ypos,
int width, int height);
~BasicFrame();
};
#endif

这是头文件。 在这个基本的程序里我们声明了两个类:

  • 继承于wxAppBasicApplication
  • 继承于wxFrameBasicFrame

我们为BasicFrame声明了构造函数和析构函数,但对于BasicApplication我们唯一做的就是重载了Oninit()方法。 注意,因为我们是在重载,所以我们把该方法声明为虚拟的(virtual)。

 #include <wx/wx.h>
#include "basic.h"
 IMPLEMENT_APP(BasicApplication)
 bool BasicApplication::OnInit()
{
BasicFrame *frame = new BasicFrame("Basic", 50, 50, 450, 300);
frame->Show(TRUE);
SetTopWindow(frame);
return TRUE;
}
 BasicFrame::BasicFrame (const wxChar *title, int xpos,
int ypos, int width, int height)
: wxFrame ( (wxFrame *) NULL, -1, title, wxPoint(xpos, ypos),
wxSize(width, height) )
{
}
 BasicFrame::~BasicFrame() { } 

这是实现,类的定义声明在basic.h里。

要注意的第一件事是宏(macro)

IMPLEMENT_APP(BasicApplication)

依据我们的观点,它构造了BasicApplication对象而且为我们的应用程序提供了main入口。 它虚拟地代替了我们前面的课程里在函数 int WINAPI WinMain( ... )中所做的所有的工作。

方法OnInit()创建了BasicFrame的一个实例,使用了默认的x和y, width(宽度)和height(高度),以及title(标题)。 它然后调用方法Show()来显示框架(frame)。 如果你查看wxFrame类,你会找不到方法Show()。wxFrame继承于wxWindow,而Show()是wxWindow的成员函数。 作为初学者,你需要记住这一点——因为许多类的都继承于其它类,所以不要忽略可能是父类提供的方法。

OnInit()也调用了wxApp的一个成员SetTopWindow()

构造函数和析构函数没有增加任何新的动作给我们的BasicFrame类。

 #include "wx/msw/wx.rc" 
最后一个相关的文件是资源文件。 在这个简单的例子里,我们没有增加任何自己的资源文件,不过你或许经常使用资源文件,而且里边至少包含这样一行:

#include "wx/msw/wx.rc"

在后面的例子里,我们会添加自己的资源。


所有剩下的工作就是建立和运行程序了。



使用MingW来建立wxWidgets程序

wxWidgets发行包里有许多的实例,而且所有的实例都有针对不同平台的make文件。 尽管这是个产生程序的很好的方法(因为用户不必在意指定所有的确定生成何种目标程序的细节),但我必须承认我发现它让人有点迷惑。 正如我随意感觉到的一样,也有一个不利的地方,那就建立(build)的过程必须要指定包含文件和库在什么地方。 我发现把wxWidgets包含文件放在标准的包含目录,而把wxWidgets库放在标准库目录里会更有帮助。 在建立和安装好库后,我会把它和wx包含目录移动到标准位置里。 在Windows系统里该位置在MingW目录里(译者注:我的MingW安装在E:/mingw/bin;而wxWidgets安装目录是F:/wxWidgets-2.5.2),而在Linux系统里它可以是在/usr或者/usr/local树里(usr/lib, /usr/include 或 /usr/local/lib, /usr/local/include)。

重新调整库和包含文件位置的主要好处是它可以排除可能给初学者带来的困惑。 这个完成后,我们现在使用下面的make文件来建立(build)程序(译者注:为了适应最新版本,所以做了较大的改动,以后的实例都会在些make文件的基础上进行修改使用):

 PROGRAM = basic
OBJECTS = ${PROGRAM}.o ${PROGRAM}_resources.o
RC = windres.exe
CC = g++
INCLUDES = -IF:/wxWidgets-2.5.2/include -IF:/wxWidgets-2.5.2/lib/gcc_lib/mswd -I.
LIBS = -lwxmsw25d_core -lwxbase25d -lwxtiffd -lwxjpegd -lwxpngd / -lwxzlibd -lwsock32
-lwxregexd -lwxexpatd -lkernel32 -luser32 / -lgdi32 -lcomdlg32 -lwinspool -lwinmm
-lshell32 -lcomctl32 -lole32 / -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lodbc32
RESSW = ${INCLUDES} --use-temp-file --define __WXMSW__
CCSW1 = -LF:/wxWidgets-2.5.2/lib/gcc_lib -g -O0 -DHAVE_W32API_H -D__WXMSW__ / -D__WXDEBUG__ -Wall
CCSW2 = -LF:/wxWidgets-2.5.2/lib/gcc_lib -Wl,--subsystem,windows -mwindows
.SUFFIXES: .o .cpp
all: ${OBJECTS} $(CC) -o $(PROGRAM) ${OBJECTS} ${CCSW2} ${LIBS}
.cpp .o: $(CC) ${CCSW1} ${INCLUDES} -c -o $@ ___FCKpd___3lt;
${PROGRAM}_resources.o: $(RC) ${RESSW} ${PROGRAM}_resources.rc $@
.PHONY : clean
clean: echo cleaning up
rm $(OBJECTS)
rm *.$
rm ${PROGRAM}.exe
(皿按:由于对Makefile结构还不够熟悉,排版整理中可能带入错误,)


建立(build)程序:
  1. 在一个单一目录里创建资源文件
    • basic.h
    • basic.cpp
    • basic_resources.rc
    • Makefile
  2. 在存放那些文件的目录里运行make
    • make
  3. 运行程序
    • basic

我们使用了的wxWidgets类

我们只使用了两个类:

  • wxApp
  • wxFrame

我们从那里继承了自己的类了BasicApplication和BasicFrame。 我会详细说明两个类,不过你也可以阅读wxWidgets文档里的更多完整的描述。

wxApp

wxApp类包含了大约30多个可以访问的成员,不过在这里我们并不需要查看wxApp里的任何细节。 后面在我们使用wxWidgets事件系统完成任务时,我们会再讨论wxApp。

wxFrame

因为wxFrame类所做工作的“可见性(visible)”更强,所以我们要花费一点点的时间来看看它的一些属性。

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 = "frame" )

我们的BasicFrame构造函数只提供了四个常见的参数: 标题(title),座标x和y,以及宽度(width)和高度(height)。

wxFrame构造函数还有其它的参数: wxWidgets指针、样式(style)、名字(name)和wxWidgetsID,最后那个是个整数,而且如果它为-1的话,就使用默认值。 提供自己的ID有时会很有用。 指针会指向父窗口,如果有的话。 在这里,指针为空(NULL),即没有父窗口。 名字参数可以象参数ID一样,由程序员来提供,在引用一个框架(frame)也许会有用处。

框架(frame)样式可以各式各样:

窗口样式

  • wxDEFAULT_FRAME_STYLE 可以被定义为 wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxRESIZE_BOX | wxSYSTEM_MENU | wxCAPTION。
  • wxICONIZE 图标化(最小化)显示框架(frame)。 仅限于Windows。
  • wxCAPTION 在框架(frame)上显示标题。
  • wxMINIMIZE 等效于 wxICONIZE。 仅限于Windows。
  • wxMINIMIZE_BOX 在框架上最小化显示盒框(box)。
  • wxMAXIMIZE 最大化显示框架(frame)。 仅限于Windows。
  • wxMAXIMIZE_BOX 在框架上最大化显示盒框(box)。
  • wxSTAY_ON_TOP 保持在其它窗口的上方。 仅限于Windows。
  • wxSYSTEM_MENU 显示系统菜单。
  • wxSIMPLE_BORDER 无边界显示或无任何修饰。 仅限于GTK和Windows。
  • wxRESIZE_BORDER 在窗口四周显示可变大小边界(仅限于Unix)。
  • wxFRAME_FLOAT_ON_PARENT 让框架(frame)位于父窗口z轴方向的上方,而不是显示在任务栏上。 如果没有这个样式,建立为最上层窗口的框架可能被父窗口挡住,而且框架的标题也会显示在任务栏。 限于Windows和GTK。
  • wxFRAME_TOOL_WINDOW 建立一个带有小标题栏的框架(frame);框架(frame)标题不会出现在任务栏。 仅限于Windows。

一个框架(frame)样式是一个或多个样式的“或(OR)”运算。 在没有定义样式时(如我们的BasicFrame),就使用默认的。例如BasicFrame会有一个最小化的盒框,一个最大化的盒框,一个系统菜单,一个标题而且可以改变大小。

要做的修改……
 BasicFrame::BasicFrame (const wxChar *title, int xpos, int ypos, int width, int height)
: wxFrame ( (wxFrame *) NULL, -1, title, wxPoint(xpos, ypos),
wxSize(width, height), wxSIMPLE_BORDER ) ...

这样你可以看到不同样式的不同效果;象这里显示的那们,修改BasicFrame的构造函数,这样一个样式就会做为参数传递给wxFrame构造函数。



在wxFrame的成员中,大约有二三十个是方法:

  • CreateStatusBar
  • CreateToolBar
  • GetTitle
  • SetIcon
  • SetMenuBar
  • SetStatusBar
  • SetStatusText
  • SetToolBar
  • SetTitle

在后面的部分,你会使用它们中的大部分,不过现在有个使用SetTitle和GetTitle成员函数的练习。

框架(frame)标题和框架(frame)名字
 BasicFrame::BasicFrame (const wxChar *title, int xpos, int ypos, int width, int height)
: wxFrame( (wxFrame *) NULL, -1, title, wxPoint(xpos, ypos),
wxSize(width, height), wxDEFAULT_FRAME_STYLE, "Fred" )
{
}
为了传递名字给wxFrame的构造函数,该构造函数已经作了修改。 现在新增这样一行:
 frame->SetTitle(frame->GetTitle() + " " + frame->GetName()); 

到函数BasicApplication::OnInit(),并且在frame->Show(true)一行的前面。

建立运行程序,你就会看到效果了。 方法GetName()是从哪里来的呢?




总结

在这个部分,你已经对wxWidgets有了大致的了解。 你见到了基本的wxWidgets框架,而且对它的体系结构有了一定的概念。 不要忘了查看wxWidgets文档的类参考手册。 刚开始你可能会发觉它让人有点迷惑,不过在练习之后,效果就会不同了。 同时我也建议,在机会合适的时候(应该经常有的),你应该看看wxWidgets的源代码。 在里边,你会发现许多有用的注释,同时也会开始领悟这个优秀软件包里所蕴藏的精髓 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章