nullnull图形界面Qt程序
牛建伟
邹 琪嵌入式系统课程——实验五null实验目的
实验内容
Qt介绍
Qt编程特点
实验步骤
实验目的实验目的了解在Linux下安装Qt以及Qt/Embedded的基本步骤
学会在Qt/E平台下使用Virtual framebuffer显示程序结果实验内容实验内容在Linux系统的宿主PC下,编译和使用Qt/E平台
在Qt/E平台下编译和运行一个程序使用Virtual framebuffer显示运行结果Qt 简介Qt 简介Qt是Trolltech公司的标志性产品,是一个跨平台的C++图形用户界面(GUI)工具包
Qt应用程序接口与工具兼容于所有支持平台,让开发员们掌握一个应用程序接口,便可执行与平台非相关的应用开发与配置
Qt/Windows (Windows XP, 2000, NT 4, Me/98)
Qt/Mac (Mac OS X)
Qt/X11 (Linux, Solaris, HP-UX, IRIX, AIX等)
Qt对不同平台的专门API进行了专门的封
装(文件处理,网络等)Qt 特征(1)Qt 特征(1)面向对象
Qt具有模块设计和注重软件构件或元素的可重用行的特点
构件支持
Qt提供信号(signal)和插槽(slot)概念,这是一种类型安全的方法,它允许回调,并支持对象之间在彼此不知道对方信息的情况下进行合作,这使得Qt非常适合于真正的构件编程
友好的联机帮助
Qt提供了大量的联机参考文档,有超文本HTML方式,也有Unix帮助页man手册页和补充说明。并且对于初学者,其中的指南将一步步介绍如何进行Qt编程
Qt 特征(2)Qt 特征(2)便利性
由于Qt是一种跨平台的GUI工具包,它对编程者隐藏了在处理不同窗口系统时潜在的问题,Qt定义了一些类来隐藏在不同操作系统上不同处理方式下的细节问题
用户自定义
使用其他的一些工具包经常会遇到这样一种情况,没有真正适合需求的组件,声称自定义的组件对用户来说就像一个黑匣子。而在Qt中生成用户自定义的组件非常简单,而且易于修改组件的行为
国际化
Qt为本地化应用提供了完全的支持,所有用户界面文本都可以基于消息翻译
被翻译成各国语言,Qt还支持双字节16bit国际字符
Qt 特征(3)Qt 特征(3)丰富的API函数
Qt为专业应用提供了大量的函数,在Qt的API中含有大约250个C++类,大多数的类都是GUI专有的
可用户化外观
Qt支持主题,基于Qt的应用程序能够在Windows外观、Motif外观,以及其它一些用户化外观主题之间切换
完整的一套组件工具
Qt编程的基本模块称之为组件,组件是用户界面的组成部分,Qt含有用来创建专业外观的用户界面所需要的所有组件Qt 编程特点Qt 编程特点1. 初始化
在Qt应用程序中,首先要创建一个QApplication对象,QApplication类负责图形用户界面应用程序的控制流和主设置,在main.cpp中定义如下:
int main(int argc, char **argv) {
QApplication a(argc, argv);
……
}null1. 初始化
QApplication包含在main()函数的事件循环体中,对所有来自Window系统和其它源文件的事件进行处理和调度,还包括处理应用程序的初始化和结束,并且提供会话管理。
在Qt应用程序中,不管有多少个窗口,QApplication对象只能有一个,而且必须在其他对象之前创建。
QApplication类中封装了很多函数,其中包括:
系统设置:setFont() 用来设置字体
事件处理:sendEvent() 用来发送事件
GUI风格:setStyles() 设置图形用户界面的风格
颜色使用:colorSpec() 用来返回颜色文件
文本处理:translate() 用来处理文本信息
创建组件:setmainWidget() 用来设置窗口的主组件
……null2. 窗口的创建
在Qt程序中,创建窗口比较简单,只要在main.cpp文件中为ApplicationWindow建立一个指针:
ApplicationWindow *mw = new ApplicatonWindow();
ApplicationWindow是在Application.h中定义的类,它是一个QmainWindow的继承类
3. 组件的创建
组件的创建需要调用相应组件的类,并在头文件中包含此类的头文件或者创建自定义类,继承以后组件类的功能
#include “qpushbutton.h”
class hello::public Qwidget
{
……
}null3. 组件的创建 hello类继承了Qwidget类的特征,并加入了自定义的特征功能,同样需要在头文件中包含此类的头文件
在main.cpp的函数中需要创建hello类的实例,或创建QPushButton类的实例,才可以使用
hello h(string);
QPushButton hello(“Hello,world!”,0);
如果组件本身可以作为主窗口,则无需设置主窗口。在上例中,下压按钮创建时其构造函数中的第二个参数为0,表示按钮所在窗口为主窗口,不需要设置主窗口。否则需要调用QWidget成员函数setMainWidget()来进行设置
h.setMainWidget(&h);
组件创建时一般是不可见的,这样的好处在于避免大量组件创建时造成的屏幕闪烁现象,要使组件可见需要调用QWidget类的成员函数show()来显示组件
h.show();null4. 事件 在X程序中,敲击键盘,鼠标指针在窗口中的移动或鼠标按键动作等,都是事件
在Xt中提供了提供了一种叫做回调的事件处理方式。它通过翻译表,将事件映射为相应的动作,当组件得到事件通知,就去表中找出相应的动作例程进行处理。这种机制需要应用程序注册有关组件的回调函数或普通的事件处理函数,以分发循环Xt的事件
Qt事件的处理过程:QApplication的事件循环体从事件队列中拾取本地窗口系统事件或其他事件,译成QEvent(),并送给QObject::event(),最后送给QWidget::event()分别对事件处理
其实在Qt程序中,事件处理的方式也是回调,但与以往所不同的是,事件的发出和接收采用了信号(signal)和插槽(slot)机制,无须调用翻译表。利用信号和插槽进行对象间的通信是Qt的最主要特征之一。null4. 事件
当对象状态发生改变的时候,发出signal通知所有的slot接收signal,尽管它并不知道哪些函数定义了slot,而slot也同样不知道要接收怎样的signal
signal和slot机制真正实现了封装的概念,slot除了接收signal之外和其它的成员函数没有什么不同,而且signal和slot之间也不是一一对应Signal和Slot的声明(1)Signal和Slot的声明(1)在Qt程序设计中,凡是包含signal和slot的类中都要加上Q_OBJECT的定义,下面的例子给出了如何在一个类中定义signal和slot:
class Student : public QObject
{
Q_OBJECT
public:
Student() { myMark = 0; }
int mark() const { return myMark; }
public slots:
void setMark(int newMark);
signals:
void markChanged(int newMark);
private:
int myMark;
};Signal和Slot的声明(2)Signal和Slot的声明(2)signal的发出一般在事件的处理函数中,利用emit发出signal,在下面的例子中在在事件处理结束后发出signal
void Student::setMark(int newMark)
{
if (newMark!= myMark) {
myMark = newMark;
emit markChanged(myMark);
}
}
Signal和Slot的连接(1)Signal和Slot的连接(1)在signal和slot声明以后,需要使用connect()函数将它们连接起来。connect()函数属于QObject类的成员函数,它能够连接signal和slot,也可以用来连接signal和signal
函数原形如下:
bool connect ( const QObject * sender, const char * signal,const char * member ) const
其中第一个和第三个参数分别指出signal和slot是属于那个对象或组件
Signal和Slot的连接(2)Signal和Slot的连接(2)在使用connect()函数进行来接的时候,还需要用到SIGNAL()和SLOT()这两个宏,使用方法如下:
QLabel *label = new QLabel;
QScrollBar *scroll = new QScrollBar;
QObject::connect( scroll,SIGNAL(valueChanged(int)),
label, SLOT(setNum(int)) );
Signal和Slot的连接方式(1)Signal和Slot的连接方式(1)Signal和Slot的连接方式(2)Signal和Slot的连接方式(2)同一个信号连接多个插槽
connect(slider, SIGNAL(valueChanged(int)),spinBox,
SLOT(setValue(int)));
connect(slider,SIGNAL(valueChanged(int)),this,
SLOT(updateStatusBarIndicator(int)));
多个信号连接到同一个插槽
connect(lcd, SIGNAL(overflow()),this,SLOT(handleMathError()));
connect(calculator, SIGNAL(divisionByZero()),this,
SLOT(handleMathError()));
Signal和Slot的连接方式(3)Signal和Slot的连接方式(3)一个信号连接到另一个信号
connect(lineEdit, SIGNAL(textChanged(const QString &)),this, SIGNAL(updateRecord(const QString &)));
取消一个连接
disconnect(lcd,SIGNAL(overflow()),this,SLOT(handleMathError()));
取消一个连接不是很常用,因为Qt会在一个对象被删除后自动取消这个对象所包含的所有的连接退出事件程序退出事件程序退出事件程序,只需要在程序结束时返回一个exec(),例如:
return a.exec();
其中a为QApplication的实例,当调用exec()将进入主事件的循环中,直到exit()被调用或主窗口部件被销毁
整个Qt程序的执行过程整个Qt程序的执行过程实验步骤(1)实验步骤(1)arm-linux-gcc-3.4.1.tar.bz2
编译qt/embedded环境和相关程序必须使用3.X版本的arm-linux-gcc来进行交叉编译。
安装arm-linux-gcc-3.4.1
从ftp或者光盘资料中得到arm-linux-gcc-3.4.1.tar.bz2
从ftp://embedded:embedded@192.168.1.54下载到/root
在root的主目录里面解压;
[minjun@localhost ~]$ tar jxf arm-linux-gcc-3.4.1.tar.bz2 -C /
设置环境变量
将arm-linux-gcc的路径加入PATH中,更改当前用户的.bashrc文件,在该文件中增加一行脚本:
export PATH=/usr/local/arm/3.4.1/bin:$PATH
使环境变量立即生效
[minjun@localhost ~]$ source .bashrc
实验步骤(1)实验步骤(1)解压缩qt-embedded-env.tar.gz
该文件可以从ftp://embedded:embedded@192.168.1.54下载。 针对redhat9的环境,将这次实验所需的tmake-1.13、qt-x11-2.3.2和qt-embedded-2.3.10预先编译后,打包成qt-embedded-env.tar.gz。实验时只要在/root目录下解压缩后设置相关环境变量,就可以进行qt/embedded程序的开发。实验步骤(2)-安装qt embedded开发环境实验步骤(2)-安装qt embedded开发环境在当前用户的主目录内,解压qt-embedded-env.tar.gz
[minjun@localhost ~]$ tar zxf qt-embedded-env.tar.gz
在解压后会得到两个目录qt/ 和 qtopia_env/;
其中qtopia_env/下面的文件是用来在开发程序时配置环境变量的
qvfb.sh -设置PC上的X11 qvfb环境,包括需要的库和tmake环境变量等
======================
target.sh -设置交叉编译时需要的环境变量,包括tmake的环境变量等
其中qt/目录下有三个子目录,分别是
qt-2.3.2
qt-2.3.10 -编译X11 qvfb环境下程序所需要的qte环境
qt-embedded-2.3.10 - 交叉编译ARM开发板上程序所需要的qte环境实验步骤(3)-编写运行qvfb环境下的程序实验步骤(3)-编写运行qvfb环境下的程序设置环境变量
相关的环境变量设置在qtopia_env/目录下的qvfb.sh中
[minjun@localhost qtopia_env]$ source qvfb.sh
运行qvfb程序
[minjun@localhost qt-2.3.10]$ qvfb &
默认启动时,qvfb窗口大小为240×320
可以在启动时指定参数:
qvfb -width 640 -height 480 &
实验步骤(3)-编写运行qvfb环境下的程序实验步骤(3)-编写运行qvfb环境下的程序接着,可以运行qt-2.3.10/examples/里面的example程序
[minjun@localhost launcher]$ launcher -qws 实验步骤(3)编写运行qvfb环境下的程序实验步骤(3)编写运行qvfb环境下的程序下面通过编写一个“Hello Embedded”程序来了解Qt。
首先新建一个目录(如hello):在hello/目录下建立如下文件:#include
#include
int main(int argc, char **argv)
{
QApplication app(argc,argv);
QLabel *hello = new QLabel("hello Qt/Embedded!",0);
app.setMainWidget(hello);
hello->show();
return app.exec();
}分析hello.cpp分析hello.cpp程序第1 行和第2 行包含了两个头文件,这两个头文件中包含了QApplication 和 QLabel类的定义。
第5 行创建了一个QApplication 对象,用于管理整个程序的资源,它需要2 个参数,因为Qt 本身需要一些命令行的参数。
第6 行创建了一个用来显示Hello Qt/Embedded!的部件。在Qt 中,部件是一个可视化用户接口,按钮、菜单、滚动条都是部件的实例。部件可以包含其它部件,例如,一个应用程序窗口通常是一个包含QMenuBar、QToolBar、QStatusBar 和其它部件的一个部件。在QLabel 函数中的参数0 表示,这是一个窗口而不是嵌入到其它窗口中的部件。
第7 行设置hello 部件为程序的主部件,当用户关闭主部件后,应用程序将会被关闭。如果没有主部件的话,即使用户关闭了窗口程序也会在后台继续运行。
第8 行使hello 部件可视,一般来说部件被创建后都是被隐藏的,因此可以在显示前根据需要来订制部件,这样的好处是可以避免部件创建所造成的闪烁。
第9 行把程序的控制权交还给Qt,这时候程序进入就绪模式,可是随时被用户行为激活,例如点击鼠标、敲击键盘等。实验步骤(3)编写运行qvfb环境下的程序实验步骤(3)编写运行qvfb环境下的程序程序的编译和运行
在配置好环境变量后,要在qvfb中运行程序需要如下的步骤
1. 生成工程文件(.pro)
[root@localhost ~]$ progen -t app.t -o hello.pro
2. 生成Makefile文件
[root@localhost ~]$ tmake -o Makefile hello.pro
3. 编译
[root@localhost ~]$ make
4. 运行(确保qvfb 在后台运行)
[root@localhost ~]$ ./hello -qws实验步骤(4)用QT Designer形界面实验步骤(4)用QT Designer设计图形界面使用Qt Designer可以方便地设计出图形界面,一般需要如下的步骤
创建和初始化子部件
设置子部件的布局
设置Tab键的次序
建立信号与插槽的连接
下面通过一个简单的例子来体验一下Qt Designer的使用
涉及的控件:
一个dial控件(上面的控件)
一个Slider控件(下面的控件)
实现的功能
拖动slider时,dial中的指针会随着转动
用鼠标拖动dial中的指针的时候,slider指示会变化实验步骤(4)用QT Designer设计图形界面实验步骤(4)用QT Designer设计图形界面启动Qt Designer (在$QT2DIR/bin里面,QT2DIR即qt-2.3.2/所在的目录)
[root@localhost test]# $QT2DIR/bin/designer
新建一个dialog
实验步骤(4)用QT Designer设计图形界面实验步骤(4)用QT Designer设计图形界面将所需的控件加入到dialog中
调整布局,使用工具栏上面的布局的控件进行调整,右图使用实验步骤(4)用QT Designer设计图形界面实验步骤(4)用QT Designer设计图形界面建立信号与插槽的连接
首先是slider发送signal、dial接收的情况
点击signal/slot的图标
在鼠标左键被按下的情况下连接slider和dial控件,出现如下对话框
在signal栏中选择vlaueChanged(int),在slot栏中选择setValue(int)
然后点击connect按钮
得到连接
同理,可以得到dial
发送信号,而slider
接收的情况
实验步骤(4)用QT Designer设计图形界面实验步骤(4)用QT Designer设计图形界面保存ui文件
将生成的ui文件保存到项目所在目录中(请专门建立一个项目的目录,里面不要有无关的文件),比如存为form.ui
根据ui文件编写包含main函数的cpp文件
内容如下
#include
#include “form.h“ /*头文件名称与ui文件名称相同*/
int main(int argc, char** argv) {
QApplication app(argc, argv);
Form1 form; /*默认创建的类是Form1,可以在Designer的属性窗口中进行修改*/
app.setMainWidget(&form);
form.show();
return app.exec();
}实验步骤(5)编译和运行程序实验步骤(5)编译和运行程序为qvfb编译程序
首先设置环境变量(qtopia_env/目录下的qvfb.sh):
[root@localhost: test] source ~/qtopia_env/qvfb.sh
进入项目的目录
[root@localhost: test] progen -t app.t -o form.pro
[root@localhost: test] tmake -o Makefile form.pro
[root@localhost: test] make
得到编译完成的二进制文件
运行如右图所示
[root@localhost: test]./form -qws实验步骤(5)编译和运行程序实验步骤(5)编译和运行程序为目标板编译程序
首先设置环境变量(qtopia_env/目录下的target.sh):
[root@localhost: test] source ~/qtopia_env/target.sh
进入项目的目录
[root@localhost: test] progen -t app.t -o form.pro
[root@localhost: test] tmake -o Makefile form.pro
[root@localhost: test] make
得到编译完成的二进制文件,将其上传到目标板上
设置相应的环境变量(见下一页)
运行程序
[mnt/yaffa ] ./form –qws
结构如下页图所示
实验步骤(5)-设置qt embedded运行环境实验步骤(5)-设置qt embedded运行环境将qt-embedded-2.3.10/lib/目录下的libqte.so.2.3.10传到开发板的/mnt/yaffs/Qtopia/lib目录下面,并建立如下的连接
[/mnt/yaffs/Qtopia/lib] ln -sf libqte.so.2.3.10 libqte.so.2.3
[/mnt/yaffs/Qtopia/lib] ln -sf libqte.so.2.3.10 libqte.so.2
[/mnt/yaffs/Qtopia/lib] ln -sf libqte.so.2.3.10 libqte.so
为了能够运行qt embedded的程序,请在目标板上设置如下的环境变量
export QTDIR=/usr/qpe
export KDEDIR=/usr/qpe
export LD_LIBRARY_PATH=/usr/qpe/lib
export QWS_MOUSE_PROTO=“TPanel:/dev/input/event0 USB”
实验步骤(5)编译和运行程序实验步骤(5)编译和运行程序在目标板上的操作需要USB鼠标的支持!
null考试时间:7月10日上午8:30-11:00
地点:主M405null开始实验