基于Qt4的图形用户界面程序设计与游戏开发

2011-03-17 07:20黄艳芳
电子设计工程 2011年17期
关键词:工具栏控件小球

黄艳芳

(电子科技大学 通信与信息工程学院,四川 成都 611731)

图形用户界面是用户与计算机进行交互的操作方式,即用户与计算机之间互相传递信息的方式,它因美观、大方、简单易用而深受广大用户的喜爱。由挪威TrollTech公司开发的Qt是一个用于跨平台的图形界面程序开发的C++工具包,提供给应用程序开发者建立图形用户界面所需的所有功能。Qt是使用源代码级“一次编写,随处编译”的方式用于构建多平台图形用户界面程序,它完全面向对象且很容易扩展,提供给应用程序开发者建立艺术级图形用户界面所需的功能,提供了信号与槽的机制替代回调函数,使组件间信号传递更安全、简单,因此,它已经成为全世界范围内数千种成功的应用程序的基础,为世界上数千个最大的公司,包括IBM、摩托罗拉和夏普等提供开发软件[1]。游戏需要给玩家提供艺术级图形用户界面,让玩家不仅使用方便,更要达到视觉上的愉悦。因此,使用Qt开发游戏是一个不错的选择。

1 Qt4编程相关技术

1.1 信号与槽(signals and slots)

信号和槽机制是Qt编程的基础。这个机制可以让编程人员把这些互不了解的对象绑定在一起[2]。信号是一个特定的标识;一个槽就是一个函数,槽和普通的C++成员函数几乎是一样的——可以是虚函数;可以被重载;可以是公有的、保护的或者私有的,并且也可以被其他C++成员函数直接调用;还有,它们的参数可以是任意类型。唯一不同的是,槽还可以和信号连接在一起。当某个事件出现时,通过发送信号,可以将与之相关的槽函数激活,即执行槽函数代码。在程序中,使用 QObject::connect()函数来将某个信号和某个槽进行关联,而信号和槽之间的真正关联是由Qt的信号和槽机制来实现的。 connect函数语法如下:connect(sender,SIGNAL(signal),receiver,SLOT(slot))。 sender和 receiver是 QObject对象指针,signal和slot是不带参数的函数原型。

信号和槽的关联关系可以有几种模式:1)一个信号和一个槽关联;2)一个信号和多个槽关联,当发射这个信号的时候,会以不确定的顺序一个接一个地调用这些槽;3)多个信号和一个槽关联,无论发射的是哪一个信号,都会调用这个槽。另外,一个信号还可以与另外一个信号相连接,当发射第一个信号时,也会发射第二个信号,例如:connect(lineEdit,SIGNAL(textChanged(constQString &)),this,SIGNAL(update-Record(constQString&)))。信号与信号之间的连接和信号与槽之间的连接有时是难以区分的。

信号与槽除了可以在程序中用connect函数手动关联外,Qt的元对象还提供了信号与槽的自动关联。对于Qt窗口部件已经提供的信号,如果能按下面的规则命名槽函数,那么Qt就能够自动进行关联:

void on_<窗口部件名>_<信号名称>_(<信号参数>)

本文设计的单机小游戏Lines中,对所有控件pushButton采用的都是自动关联信号与槽的方式 void_on_pushButton_clicked(),这样更加简单快捷。

1.2 事件

“事件”功能,简单来说就是当一个事件产生后,相关控件作出回应。Qt事件的处理过程是,首先QApplication的事件循环体从事件队列中拾取本地窗口系统事件或者其他事件 ,译成 QEvent;然 后 ,把 QEvent送 给 QObject:event();最后,再送给 QWidget:event(),对事件进行处理[2]。 Qt已经将上述那些繁琐的调用步骤封装,极大减轻了编程人员的负担。

1.3 绘图

Qt的2D图形系统的基础是类QPainter,QPainter能够绘制各种几何图形(点,线,矩形,椭圆,圆弧,弦,扇形,多线段,贝赛尔曲线),还能绘制位图,图像和文字[3]。在控件上绘图时,先创建一个QPainter,把绘图设备指针传给QPainter对象,然后在绘图函数 paintEvent(QPaintEvent*event)中,通过函数painter.setPen()设置画笔的颜色、大小和所绘曲线类型;通过函数painter.draw函数绘制需要的图形;通过函数QBrush brush(QColor())设置画刷颜色,用画刷给图形填充颜色。

paintEvent()函数是一个事件处理函数,在控件需要重新绘制的时候调用。Qt中很多情况下都会产生绘制事件,调用paintEvent()函数:

1)当控件第一次显示时,Qt自动产生绘制事件使控件绘制自身;

2)当控件尺寸发生变化时,系统产生绘制事件;

3)如果控件被其他的窗口遮住,窗口移走时,产生绘制被遮住部分的事件。

4)如 果 调 用 了 QWidget:update 和 QWidget:repaint()函数,产生绘制事件。

update()函数和 repaint()函数有所不同。 repaint()立刻产生绘制事件,重新绘制控件;而调用update()后,只是交给Qt一个产生绘制事件的计划。如果控件在屏幕上不可见,那么这两个函数什么都不做。如果update()被调用了多次之后,Qt就把这几个连续的绘制事件合为一个事件避免闪烁。

本文设计的单机小游戏Lines,就是通过this->update()函数来重绘游戏区的。

1.4 QSound音频

Qt提供了在大多数GUI应用程序中通常都需要的操作:异步播放声音文件。播放声音有两种方式[4]:

1)QSound:play("debug/sound/click.wav");2)QSound:bells("debug/sound/click.wav");bells.play();第二种方式播放声音会消耗更多内存,但依靠底层平台的音频设备,比起第一种方式播放声音更直接。在微软windows下使用的底层多媒体系统,仅支持WAVE格式的声音文件。

1.5 定时器(QTimer)

Qt中的QTimer类提供了定时器信号和单触发定时器[3]。它在内部使用定时器事件来提供更通用的定时器。QTimer的使用比较简单:创建一个QTimer,使用start()来开始并且把它的timeout()连接到适当的槽。当这段时间过去了,它将会发射 timeout()信号。

QTimer的精确度依赖于底下的操作系统和硬件。绝大多数平台支持20ms的精确度,一些平台可以提供更高的。如果Qt不能传送定时器触发所要求的数量,它将会默默地抛弃一些。一些操作系统限制可能用到的定时器的数量,Qt会尽力在限制范围内工作。当QTimer的父对象被销毁时,它也会被自动销毁。

1.6 按钮(QpushButton)

QPushButton窗口部件提供了命令按钮,主要用来提供点击动作。。

控件pushButton用自动关联信号与槽的方式void_on_pushButton_clicked()关联信号与槽。当按钮被鼠标、空格键或者键盘快捷键激活,它发射clicked()信号,连接这个信号来执行按钮的操作。

2 游戏设计及实现

2.1 游戏概述

如图1所示,游戏中有7种颜色的小球,81个可放置小球的位置。每移动一个小球,随机发射3个小球,每个小球的颜色是七种颜色中的任意一种。这3个小球随机放置在81个位置中没有小球的地方。游戏目标是将同一颜色的球排在同一直线上(横、竖、斜着排都可以)。当5个或5个以上颜色相同的小球排在同一直线上时,小球会被移除,并得分。同一直线上相同颜色小球个数越多,得分越高。当81个位置都布满小球时,游戏结束。

图1 游戏主界面Fig.1 Main interface of the game

2.2 开发平台的建立

目前,在Windows平台下使用Qt非常方便,不再像以前一样,需要再经过几个小时的自己编译。目前比较流行的有把Qt的开发环境集成到Visual Studio 2008环境中[5]和直接使用Qt Creator而仅借用Visual Studio 2008的编译器。本文中的界面构建使用的是免费的 “QtCreator+Visual Studio 2008编译器”:

1)下载并安装好Visual Studio 2008。

2)下载开源版的 qt-sdk-win-opensource-2010.04.exe,安装好。

3)设置环境变量: 右键“我的电脑”->“属性”->“高级”->“环境变量”,在PATH,INCLUDE和LIB中分别填入环境变量:

至此,开发环境搭建完成。

2.3 应用程序的设计及关键代码

通过子类化QMainWindow创建游戏应用程序的用户界面。

游戏具体代码设计与实现过程大致分为两步:1)用Qt建立GUI界面的主框架;2)调用信号与槽机制和事件功能以完善游戏的详细功能。

2.3.1 用Qt建立GUI界面的主框架

游戏的主框架如图2所示。主要有菜单栏、工具栏、图标、用以计分的标签和各种按钮。

图2 游戏主框架Fig.2 Main frame of the game

2.3.2 完善游戏的详细功能

通过信号与槽机制和事件功能,借用QTimer定时刷新程序完成菜单栏、工具栏、图标、计分、各种按钮及绘图的功能。

1)创建菜单栏和工具栏

本游戏需要一个菜单栏和一个工具栏,菜单栏提供游戏的声音、重新开始、退出及帮助等按钮;工具栏把菜单栏里的功能用图标表示出来,方便用户快速使用那些功能。菜单栏和工具栏使用了action(动作)的概念。一个action就是一个可以添加到任意菜单栏和工具栏上的项。创建菜单栏和工具栏时,按照如下步骤进行:创建并设置action->创建菜单并把action添加到菜单上->创建工具栏并把action添加到工具栏上。每选择一个菜单项,都会触发相应的槽函数。在此,对于每一个action,信号与槽的关联我们不用connect函数手动关联,而是采用自动关联的方式,即,对于“重新开始”菜单项,我们在创建该菜单项的时候,就命名为action_R:

private slots:void on_action_R_triggered();

则当选择“重新开始”菜单项的时候,此动作触发了槽函数 restart()函数:

restart()函数定义在私有类中,该函数主要作用是使游戏重新开始。

工具栏中的图标通过Qt Resource File添加到程序中。

2)鼠标点击按钮事件

界面中,先调用paintEvent()函数画出图1中蓝色方框里的81个位置;在每个位置上方分别布上一个和81个蓝色方框一样大小的pushButton按钮,按钮名称为pushButton00~80,如图2所示。小球在按钮下方的窗口上画出。用ui->pushButton->setFlat(true)把按钮设置成透明的,这样在按钮下方画图时,按钮就不会覆盖图形了。

游戏过程中,当玩家用鼠标点击相应的方块,程序就会做出相应的响应事件,程序处理这些事件来完成图形的绘制[6]。

MainWindow类的定义如下:

下面以 void on_pushButton00_clicked()为例,简要说明代码如何为绘图做准备:

void Lines :on_pushButton00_clicked () //按钮被鼠标左键点击

void Lines:on_pushButton00_clicked() 函数中,有很多变量随着鼠标的按下而改变。是否有5个或者以上相同颜色连在一起以及游戏得分可能也随着鼠标按下而改变。这些改变需要通过定时器定时去检测。检测到有变量的改变则需要重绘图形,重绘图形的指令update放在paint_show()函数中,系统通过定时器定时调用paint_show()函数[7]。

创建一个 QTimer:m_timer=new QTimer (this);

使用start()来开始并且把它的 timeout()连接到适当的槽 :connect (m_timer, SIGNAL (timeout ()),this, SLOT(paint_show())); m_timer->start(10);

槽函数:

绘图函数paintEvent()主要动态绘制3部分内容:

1)下一次出现的小球,根据m=qrand()%8得到的随机数的值绘制小球的颜色,不同的数字代表小球不同的颜色;

2)被移动后重新放置的小球和重新出现的小球,及5个或以上相同颜色小球相连时被移除的小球。这些小球是否被移除或者被绘制根据paint[i][j]的值,绘制什么颜色根据j[i][j]的值;

3)被点击小球外面的红框,是否有红框框根据p_flag[i][j]的值。

关键代码如下:

//以上绘画重新放置和重新出现的小球,及5个或以上相同颜色小球相连时被移除的小球

}

3 结束语

本文着重分析了Qt的信号与槽机制和事件功能,并详细描述了绘图函数paintEvent()、添加音频、按钮QpushButton和定时器QTimer的用法。通过设计及实现单机小游戏Lines,来表现出Qt在构建图形界面、实现事件响应、绘图、播放声音等方面的卓越特性。随着越来越多的产品需要有完美的操作界面以满足人机交互的需求,使用Qt来开发图形用户界面程序将会变得越来越广泛。

[1]张春艳.基于Qt的嵌入式图形用户界面研究与实现[D].大连:大连海事大学.2008

[2]Blanchette J,Summerfield M.C++GUIProgrammingwith Qt4[M].Prentice HallPTR.2006.

[3]蔡志明.精通Qt4编程[M].北京:电子工业出版社,2008.

[4]Trolltech.Qt-Cross-Platform C++Development-Trolltech[EB/OL].(2007).http://www.trolltech.com/products/qt/features/index.

[5]李继平,毕淑娥,易立琼,等.基于QT4与windows CE的机器人示教盒界面设计[J].现代计算机, 2010(5):175-177、187.

LI Ji-ping, BI Shu-e, YI Li-qiong,et al.Design of user interface of teaching box based on QT4 and Windows CE[J].Modern Computer,2010(5):175-177、187.

[6]Lippman B, Lajoie, Barbara E.Moo.C++Primer[M].北京人民邮电出版社,2006.

[7]谭浩强.C程序设计[M].2版.北京清华大学出版社,2002.

猜你喜欢
工具栏控件小球
“玩转”西沃白板
联想等效,拓展建模——以“带电小球在等效场中做圆周运动”为例
小球进洞了
小球别跑
小球别跑
关于.net控件数组的探讨
ASP.NET服务器端验证控件的使用
设计一种带工具栏和留言功能的记事本
基于嵌入式MINIGUI控件子类化技术的深入研究与应用
轻松DIY:用好IE8浏览器中的自定义功能等