2009年4月13日星期一

U++教程2:与U++交谈

教程1里我们已经了解了U++开发环境的基本用法,并写了一个小小的HelloWorld。
不过那真的算不上是一个程序,在这一节里,我们将让事情变的更象样一点,让我们的程序有点交互性。
U++程序与其它GUI框架一样,都需要一个主窗口来容纳各种各样的控件用来与用户进行交互。在U++中,这个主窗口是由TopWindow类来负责的,让我们来看看它是如何工作的。把教程1里的程序改成下面这样:


#include <ctrllib/ctrllib.h>
using namespace Upp;

GUI_APP_MAIN
{
TopWindow a;
a.Run();
}

编译运行一下,我们就得到了一个空白窗口:
不过这个窗口没有什么用处,它不包含任何可与用户进行交互的控件。下面我们就来看看如何让这个窗口变的生动起来。我们将在这个窗口中添加两个按钮,一个名为Hello,用来产生教程1里的Hello World对话框,一个名为Close用来退出程序。
为了向窗口添加控件,并让其可与用户交互,我们需要从TopWindow派生一个我们自己的主窗口类。类定义如下:
class HelloWindow:public TopWindow
{
private:
Button hellobtn; //建立两个按钮成员
Button closebtn;
public:
void hellofn(); //定义两个方法,将来我们要把它们与按钮联接
void closefn();
HelloWindow(); //构造函数
};

下面是HelloWindow类中成员函数的实现:
void HelloWindow::hellofn()
{
PromptOK("Hello World"); //显示对话框
}

void HelloWindow::closefn()
{
Close(); //退出程序
}

//下面是HelloWindow类的构造函数,控件的添加主要在这里进行
HelloWindow::HelloWindow()
{
Title("Hello World!").Sizeable().Zoomable(); 
SetRect(0,0,300,150);
Add(hellobtn.SetLabel("Hello").LeftPos(50,80).TopPos(50,30));
Add(closebtn.SetLabel("Close").RightPos(50,80).TopPos(50,30));
hellobtn<<=callback(this, &HelloWindow::hellofn);
closebtn<<=callback(this, &HelloWindow::closefn);
}

各种控件的添加及属性设置均在构造函数里完成,我们来详细看看这些语句的功能。
Title("Hello World!").Sizeable().Zoomable(); 
这一句用来对主程序窗口本身进行一些属性设置,在U++里这些属性的设置是可以串联进行了,因为它们在基类里的定义是返回控件本身的引用。这使得程序语句可以变得十分紧凑。在这一句里,Title用来设置主窗口的标题,Sizeable令窗口可以调整大小,Zoomable令主窗口具有最大最小化按钮。读者可以通过增减这几个属性来看看窗口的变化,以了解这些属性的实际意义。主窗口类还有许多其它的属性,这可以通过阅读U++编程手册来了解,现在我们先了解这些。

SetRect(0,0,300,150);
用来指定窗口的初始大小,要注意的是这里的窗口大小并不包括窗口的标题栏。

Add(hellobtn.SetLabel("Hello").LeftPos(50,80).TopPos(50,30));
向主窗口添加控件就通过Add方法来完成。其参数就是所要添加的控件,在这里是我们的Hello按钮。hellobtn.SetLabel("Hello")用来设置按钮上的文字,其后跟随的LeftPos与TopPos用来指定按钮在主窗口中的位置。LeftPos表示按钮与主窗口左边界的距离,TopPos则表示其与主窗口上边界的距离。这两个属性的第二个参数则是指定了按钮的大小。LeftPos(50,80)表示按钮距离主窗口左边界50个象素,按钮宽度80。TopPos(50,30)表示按钮距主窗口上边界50,按钮高度30。

hellobtn<<=callback(this, &HelloWindow::hellofn);
这一句用来指定按下按钮后要调用的函数。在u++中对事件的响应都是通过回调函数(callback)来完成的,所以在U++中 callback是一个很重要的概念,我们以后会对它进行更详细的介绍。

OK,到这里我们对主窗口的设定就基本完成了,我们只需要生成一个HelloWorld类的实例然后调用Run函数就可以了:
GUI_APP_MAIN
{
HelloWindow myapp;
myapp.Run();
}

编译运行一下试试,呵呵。我们得到了如下的界面:


点击一下按钮试试,然后再缩放一下窗口的大小看看会有什么变化。通过这些操作你会对U++如何管理界面有进一步的了解。
现在再来看一下我们的代码,噢,为按钮指定回调函数的语句显的有点太冗长了。让我们对代码进行一点调整。
首先我们在类定义中添加这条语句:
typedef HelloWindow CLASSNAME;

然后在构造函数中把指定回调函数的语句改成这样:
hellobtn<<=THISBACK(hellofn);
closebtn<<=THISBACK(closefn);

这样看上去就要简洁多了,THISBACK是u++定义的一个宏,它会自动扩展为:callback(this, &HelloWindow::hellofn)这种形式。

我们最终的代码如下:
#include <ctrllib/ctrllib.h>

using namespace Upp;

class HelloWindow:public TopWindow
{
private:
Button hellobtn;
Button closebtn;
public:
void hellofn();
void closefn();
HelloWindow();
typedef HelloWindow CLASSNAME;
};

void HelloWindow::hellofn()
{
PromptOK("Hello World");
}

void HelloWindow::closefn()
{
Close();
}

HelloWindow::HelloWindow()
{
Title("Hello World!").Sizeable().Zoomable();
SetRect(0,0,300,150);
Add(hellobtn.SetLabel("Hello").LeftPos(50,80).TopPos(50,30));
Add(closebtn.SetLabel("Close").RightPos(50,80).TopPos(50,30));
hellobtn<<=THISBACK(hellofn);
closebtn<<=THISBACK(closefn);
}

GUI_APP_MAIN
{
HelloWindow().Run(); //为了使代码更紧凑,我们使用了匿名对象。
}

OK,这篇教程就到这里了,赶快动手编译试试吧。
嗯?我听见有人说了,既然是中文教程,为啥程序界面上全是英文?呵呵,那是我为下一篇教程准备的,下一篇我们将讨论一下u++程序的国际化支持。

没有评论: