QT 3.3白皮书

来源:互联网 发布:网络理财平台骗局揭秘 编辑:程序博客网 时间:2024/05/19 20:39
QT 3.3白皮书,
http://www.trolltech.com
[3] 袁鹏飞,24小时学通qt编程,北京:人民邮电出版社,2000/11
[4] 于明俭,陈向阳,方汉, LINUX程序设计权威指南,北京:机械工业出版社,2001/4 
[5] 张娟,张雪兰,基于嵌入式的GUI应用程序的实现,《计算机应用》,2003,23(4):115-117 
作者简介:王丽洁(1981-),女,硕士研究生,研究方向为嵌入式系统的开发与应用。
作者联系方式:410073,湖南长沙国防科大四院2系,0731-4575752,13873163041,
lilywang_04601@163.com
交叉编译Qtopia的几个问题 
[url=#indexdir]Return to Top[/url]
[http://blog.csdn.net/chenrongqin/archive/2005/08/28/466936.aspx]
本文记载步骤和排错过程,用到的源码包有:qt-embedded-2.3.10-free.tar.gz、qtopia-free-source-2.1.1.tar.gz、jpegsrc.v6b.tar.gz、e2fsprogs-1.38.tar.gz。
步骤主要有:
1. 注意设置环境变量:QTEDIR、QPEDIR、PATH、LD_LIBRARY_PATH等
2. 交叉编译qte:
./configure –qconfig qpe -system-jpeg -no-xft -gif -qvfb -depths 4,8,16,32 –xplatform linux-arm-g++
3. 交叉编译qtopia
./configure -edition pda -no-qtopiadesktop -displaysize 480X640 –xplatform linux-arm-g++
在编译过程中遇到的主要错误有:
1. usr/local/hybus-arm-linux-R1.1/arm-linux/bin/ld:
warning: libjpeg.so.62, needed by /usr/local/qt-2.3.10/lib/libqte.so,
not found (try using -rpath or -rpath-link)
/usr/local/qt-2.3.10/lib/libqte.so: undefined reference to `jpeg_read_scanlines'...........................
解决方法:
从http://freshmeat.net/redir/libjpeg/5665/url_tgz/jpegsrc.v6b.tar.gz下载jpegsrc.v6b.tar.gz解压并进入解压的目录。
tar -xzf jpegsrc.v6b.tar.gz
cd jpeg-6b
[root@localhost jpeg-6b]# ./configure --enable-shared
修改生成的Makefile文件:
prefix = qt-embeddedd的文件夹路径(eg: /usr/local/qt-2.3.10)
CC= /usr/local/arm/2.95.3/bin/arm-linux-gcc
AR= /usr/local/arm/2.95.3/bin/arm-linux-ar rc
AR2= /usr/local/arm/2.95.3/bin/arm-linux-ranlib 
保存
在你的qt-embedded中建立man/man1文件家,否则安装jpeg库时会出错
[root@ localhost jpeg-6b]#mkdir -p qt-2.3.10/man/man1 
最后:
[root@ localhost jpeg-6b]# make
[root@ localhost jpeg-6b]# make install
就可以给qt-embedded添加好for arm的libjpeg库. 
把生成的库文件向下面的目录中也拷贝一份:
/usr/local/hybus-arm-linux-R1.1/arm-linux/lib 
/usr/lib
2.    qpeapplication.cpp: In method `void QPEApplication::systemMessage(const QCString &, const QByteArray &)': 
qpeapplication.cpp:2175: warning: unused variable `int old'............... 
解决方法:在$QPEDIR/src/libraries/qtopia目录下执行
cp custom-linux-ipaq-g++.cpp custom-linux-myarm-g++.cpp
cp custom-linux-ipaq-g++.h custom-linux-myarm-g++.h
3. 遇到关于libuuid的错误时.................
解决办法:交叉编译e2fsprogs-1.38:
./configure –host=arm-linux –with-cc=arm-linux-gcc –with-linker=arm-linux-ld –enable-elf-shlibs –prefix=/usr/local/qtopia-2.1.1
make
make install
这样就将libuuid库安装到了qtopia目录下。 
再执行cp –r /usr/local/e2fsprogs-1.38/lib/uuid /usr/local/qtopia-2.1.1/include 
使得qtopia能够找到头文件。
嵌入式工具QT的安装与使用 
[url=#indexdir]Return to Top[/url]
[http://blog.csdn.net/suisuibianbian/archive/2004/11/18/185923.aspx]
Qt是Trolltech公司的一个产品。Trolltech是挪威的一家软件公司,主要开发两种产品:一种是跨平台应用程序界面框架;另外一种就是提供
给做嵌入式Linux开发的应用程序平台,能够应用到PDA和各种移动设备上。Qt和Qtopia分别是其中具有代表性的两个。 
Qt是一个多平台的C++图形用户界面应用程序框架,它能给用户提供精美的图形用户界面所需要的所有元素,而且它是基于一种面向对象的思想,所以用户对其对象的扩展是相当容易的,并且它还支持真正的组件编程。 
Qt是Linux桌面环境KDE的基础。笔者认为,可以说Qt与Windows下的Mfc的实质是一样的,所以Qt最大的优点在于其跨平台性,可以支持现有的多种操作系统平台,主要有: 
◆ MS/Windows 95、Windows 98、WindowsNT 4.0、Windows 2000、Windows XP; 
◆ Unix/X11 Linux、Sun Solaris、HP-UX、Compaq True64Unix、IBM AIX、SGI IRIX和很多其它X11平台; 
◆ Macintoshi Mac OSX; 
◆ Embedded—带FramBuffer的Linux平台。 
下面简单介绍一下Qt/Embedded和Qtopia在Linux上的安装和使用,还有在开发过程中可能碰到的一些问题。

Qt 和Qtopia的安装
如果需要安装一个带FramBuffer的Qtopia平台,需要有以下软件(所列举软件以笔者使用的为例): 
◆ Qtopia 1.6.0; 
◆ Tmake 1.11; 
◆ Qt/Embedded 2.3.4(Qtopia 1.6.0是基于该开发平台上开发的);
◆ Qt/Embedded 2.3.2 for X11; 
◆ Qt 3.1.2 for X11。 
在Trolltech公司的网站上可以下载该公司所提供的Qt/Embedded的免费版本。 
Qtopia平台安装分为以下几个步骤: 
1. 解包Qtopia 
在Linux命令模式下运行以下命令: 

   
tar xfz qtopia-source-1.6.0 (解包)
cd qtopia-source-1.6.0
export QPEDIR=$PWD   (设置环境变量)
cd..
2. 安装Tmake 
在Linux命令模式下运行以下命令:
    
tar xfz tmake-1.11.tar.gz
export TMAKEDIR=$PWD/tmake-1.11
export TMAKEPATH=$TMAKEDIR/lib/qws/linux-x86-g++
export PATH=$TMAKEDIR/bin:$PATH

3. 安装Qt/Embedded2.3.4 
在Linux命令模式下运行以下命令:
    
tar xfz qt-embedded-2.3.4-commercial.tar.gz
cd qt-2.3.4
export QTDIR=$PWD
export QTEDIR=$QTDIR
export PATH=$QTDIR/bin:$PATH
export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
cp $QPEDIR/src/qt/qconfig-qpe.h src/tools/
. /configure -qconfig qpe -qvfb -depths 4,8,16,32
make sub-src
cd ..

也可以在configure的参数中添加-system-jpeg和gif,使Qtopia平台能支持jpeg、gif格式的图形。 
4. 安装Qt/X11 2.3.2 
在Linux命令模式下运行以下命令:
    
tar xfz qt-x11-2.3.2-commercial.tar.gz
cd qt-2.3.2
export QTDIR=$PWD
export PATH=$QTDIR/bin:$PATH
export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
. /configure -no-opengl
make
make -C tools/qvfb
mv tools/qvfb/qvfb bin
cp bin/uic $QTEDIR/bin
cd ..

根据开发者本身的开发环境,也可以在configure的参数中添加别的参数,比如-no-opengl或-no-xfs,可以键入./configure -help来获得一些帮助信息。 
5. 安装Qt/X11 3.1.2 
在Linux命令模式下运行以下命令: 
    
tar xfz qt-x11-commercial-3.1.x.tar.gz
cd qt-x11-commercial-3.1.x
export QTDIR=$PWD
export QT3DIR=$QTDIR
export PATH=$QTDIR/bin:$PATH
export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
./configure -thread
make
cd ..

6. 安装Qtopia 
在Linux命令模式下运行以下命令: 
    
cd qtopia-source-1.6.x
export QTDIR=$QTEDIR
export QPEDIR=$PWD
export PATH=$QPEDIR/bin:$PATH
cd src
./configure
make
  cd ../..

7. 安装Qtopia桌面 
    
cd qtopia-source-1.6.x/src
export QTDIR=$QT3DIR
./configure -qtopiadesktop
make
mv qtopiadesktop/bin/qtopiadesktop ../bin
cd ..

Qt和Qt Designer的使用 
根据上面的步骤安装完成了Qt/Embedded和Qtopia之后,就可以运行这些程序了。 
运行Qt的虚拟仿真窗口:在Linux的图形模式下运行命令qvfb&;Qtopia只是一个用Qt/Embedded开发的程序,运行Qtopia,在图形模式下运行命令: 
    
export QTDIR=$QTEDIR,
qpe &;

这样Qtopia的程序就运行在QVFB上,即Qt的虚拟仿真窗口。 
Qt/Embedded是针对嵌入式Linux而开发的一种开发工具,Qt封装了一些常用的类,而且这些类的名字都以Q字开头命名,如QString、QDialog等。这里主要介绍一下如何利用Qt Designer来设计组件,并生成相应的代码。 
在Qt中,把组件分为复合体、原始体和配件。而在Qt中,组件是由一些抽象类、复杂的组件类、管理组件几何特性的类等组成。 
Qt中有三个主要的基类:QObject、Qapplication和QWidget。 
在Qt
中编程,利用Signal和Slot进行对象之间的通信是Qt的主要特征。它与Windows中的消息机制非常类似,但是Signal和Slot机制真正
实现了一种消息的封装。当对象的状态改变时,发出Signal,通知所有的Slot接受Signal,尽管它不知道哪些函数是Slot,Slot一开始也
不知道哪些Signal可以接收。Signal和Slot之间不是一一对应的关系,一个Signal可以发给多个Slot,
Slot也可以接收多个Signal。Slot除了可以接收Signal以外,与其它的成员函数没有区别。这种机制比使用回调函数要灵活,但是会减慢程序
的运行速度。不过在现在高速CPU的面前,这种损失是无足轻重的,而且它还能保证程序的简明性和灵活性,非常便利。 
在Qt的组件中,不仅定义了常用的成员变量和成员函数,还定义了所有与该组件相关的Signal和Slot。 
要将组件组合起来,最简单的方法就是使用Qt Designer。首先要启动Qt Designer,在Linux命令模式下,键入以下命令(假设Qt安装在/usr/local下): 
    
cd qt-2.3.2/bin
./designer

这样就可以启动一个与Windows下的Delphi相类似的如图1的界面。 

   然
后新建一个QFrame,将自己需要的组件直接拖拉到这个Frame中,相信很多人都有过这样的经历,此处就不再详细描述了。完成之后存盘时,会将这个新
的组件保存为一个扩展名为.ui的文件。假设所存的文件名为test.ui,用vi
test.ui来查看这个文件,发现这是一个用xml语言写的一个文本。下面用这个test.ui生成相应的test.h和test.cpp。同样还是在
这个目录下,可以看到一个uic的工具,这个是Qt专门用来将ui文件生成.h和.cpp文件的,在终端模式下键入以下命令: 
    
./uic -o test.h test.ui
./uic -o test.h -i test.cpp test.ui


时就能看到生成了相应test.h和test.cpp,这是一个类。当然这只是一些表面的东西,还需要在这些代码中添加相应的Signal和Slot,完
成所需要的操作。值得注意的是,相应版本生成的ui最好用相应版本的uic来生成代码。如果用Qt 3.1.2的Designer生成的ui,用Qt
2.3.2的uic来生成代码,生成的代码都会是一些空函数。 
在一般的开发过程中,首先通过这个ui生成的一个类,在Qt中通常叫做
Base,如上面的例子,叫做testBase;然后再新建一个类,来继承这个Base。通常叫做实现类Impl,如testImpl。在这个实现类里面
定义所需要的成员函数、Signal和Slot,因为ui可能是经常需要改动的。如果这样做,每次只需要在Designer中修改ui,而不用去理会这些
成员函数、Signal和Slot了。 
编译一个Qt程序必然需要Makefile,在Qt中提供了一个专门生成Makefile的工具,就是tmake。用tmake需要根据编写的程序写一个.pro文件。.pro文件非常简单,有固定的格式,下面是一个例子: 
    
TEMPLATE = app
CONFIG  = qtopia warn_on release
MOC_DIR  =tmp
OBJECTS_DIR =tmp
HEADERS  =fcrs.h\ 
                  structs.h \
                  globalfunc.h \
                  globalvars.h \ 
                  testimpl.h
    SOURCES  = main.cpp \
                  globalfunc.cpp\
                  globalvars.cpp \ 
                  testimpl.cpp
INTERFACES = test.ui \
TARGET  = fcrs

生成这个.pro文件之后,在终端中键入下面的命令: 
    
tmake -o Makefile test.pro

就自动生成了一个Makefile,使用这个Makefile编译所编写的程序就可以了。
Signals and Slots in Depth 
[url=#indexdir]Return to Top[/url]
[http://blog.csdn.net/suisuibianbian/archive/2004/11/18/185923.aspx]
信号和槽机制是Qt编程的基础。它使应用程序员能够在对象之间互相不知道任何联系的情况下把这些对象帮定在一起。我们已经连接了一些信号和槽,声明了我们自己的信号和槽,执行自己的槽,发出自己的信号。让我们花点时间深入点看这个机制。
槽与普通的C++成员函数几乎一样。它们可以是virtual,overloaded,public,protected,private,并且可以被其他C++成语函数直接调用。区别是槽可以被信号连接,信号被发送将它自动调用。
connect()声明如下:
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
sender和receiver是指向QObjects的指针,signal和slot是没有参数名的函数signatures(签名)。SIGNAL()和SLOT()宏将转换它们的参数成为一个字符串。
刚才的例子中我们总是连接不同的信号到不同槽,有更多的可能去探究:
1 .     一个信号可以连接很多槽:
        connect(slider, SIGNAL(valueChanged(int)),spinBox, SLOT(setValue(int)));
        connect(slider, SIGNAL(valueChanged(int)),this, SLOT(updateStatusBarIndicator(int)));
        当信号发出,这些槽一个接一个被调用,以任意顺序。
2 .     很多信号可以连接到同样的槽:
        connect(lcd, SIGNAL(overflow()),this, SLOT(handleMathError()));
        connect(calculator, SIGNAL(divisionByZero()),this, SLOT(handleMathError()));
        其中任何一个信号发出时,这个槽被调用。
3.     一个信号可以连接到另一个信号:
        connect(lineEdit, SIGNAL(textChanged(const QString &)),this, SIGNAL(updateRecord(const QString &)));
        当第一个信号发出,第二个信号也会发出.从这点,singnal-singnal连接与signal-slot连接不能区分.
4 .    连接可以被移除:
        disconnect(lcd, SIGNAL(overflow()),this, SLOT(handleMathError()));
        这个很少需要,因为Qt在对象删除的时候自动删除所有包括对象的连接. 
当连接一个信号到一个槽(或者连接到另一个信号),它们都必须用同样的顺序有同样的参数:
        connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),this, SLOT(processReply(int, const QString &)));
异常情况,如果信号比它连接的槽更多的参数,增加的参数将直接忽略:
        connect(ftp, SIGNAL(rawCommandReply(int, const QString &)),this, SLOT(checkErrorCode(int)));
如果参数类型不符合,或者信号或槽不存在,Qt将输出一个运行时警告.同样,如果参数名被包含在信号或槽signatures(签名)里,Qt将给一个警告.
QT中的信号和槽 
[url=#indexdir]Return to Top[/url]
[http://blog.csdn.net/compiler_hdz/archive/2006/02/13/598163.aspx]
在图形界面编程中,很多时候我们希望一个可视对象发生某种变化时通知另一个或几个对象,再一个地说,我们希望任何一
类的对象能和其他对象进行通讯。例如,某个数值显示窗口负责显示某个滚动条对象的当前数值,当滚动条对象的值发生变化时,我们希望数值显示窗口能收到来自
滚动条对象发送的“数值改变”的信号,从而改变自己的显示数值。
对于类似以上的问题,较早的工具包使用“回调”的方式来实现。回调是指一个函数的指针,如果你希望一个处理函数同志你一些事件,你可以把另一个函数的指针传递给处理函数。处理函数在适当的时候会调用回调函数。
采用回调方式实现对象间的通讯有两个主要缺点,首先回调函数不是类型安全的,我们不能确定处理函数使用了正确的参数来调用回调函数,第二,回调函数和处理函数间的联系非常紧密,因为处理函数必须知道要调用哪个回调函数。
在QT开发环境中,实现对象间的通讯我们有一种称为“信号和槽”的机制可以代替回调函数。信号和槽机制用于实现对象间的通讯,是QT的一个中心特性,恐怕也是QT与其它工具包最不同的地方了。
信号和槽机制就是:当一个特定的事件发生时,一个或几个被指定的信号就被发射,槽就是一个返回值为void的函数,如果存在一个或几个槽和该信号相连接,那在该信号被发射后,这个(些)槽(函数)就会立刻被执行。

号和槽机制是类型安全的,一个信号的签名必须与它的接收槽的签名相匹配,这样编译器就可以帮助我们检查类型是否匹配。信号和槽是很宽松的联系在一起的,一
个发射信号的对象不用考虑哪个槽会接收这个信号,接收信号的槽的所在对象也不知道要连接的信号是哪个对象发射的。QT的信号和槽机制可以保证如果你把一个
信号和一个槽连接起来后,槽会在正确的时间使用信号的参数而被调用,信号和槽可以使用任何数量、类型的参数。
QT的窗口部件已经有很多预定
义的信号,也有很多预定义的槽,但我们总是通过继承来加入我们自己的信号和自己的槽,这样我们就可以处理感兴趣的信号了。凡是从QObject类或者它的
某个子类继承的所有类都可以包含信号和槽。当某个事件发生后,被指定的信号就会被发射,它不知道也没有必要知道是否有槽连接了该信号,这就是信息封装。

是可以用来接收信号的正常的对象的成员函数,一个槽不知道它是否被其它信号连接。可以把一个信号和一个槽进行单独连接,这时槽会因为该信号被发射而被执
行;也可以把几个信号连接在同一个槽上,这样任何一个信号被发射都会使得该槽被执行;也可以把一个信号和多个槽连接在一起,这样该信号一旦被发射,与之相
连接的槽都会被马上执行,但执行的顺序不确定,也不可以指定;也可以把一个信号和另一个信号进行连接,这样,只要第一个信号被发射,第二个信号立刻就被发
射。
下面看看不使用信号和槽和使用信号和槽的两个对象有什么不同。
不使用信号和槽的C++对象:
class NoSignalClass {
public:
    NoSignalClass (void) {}
    int value (void) const {return _value;}
    int setValue (int value) {_value = value;}
private:
    int _value;
}
使用信号和槽的QT对象:
class UseSignalClass {
    Q_OBJECT
public:
    UseSignalClass (void) {}
    int value (void) const {return _value;}
public slots:
    int setValue (int value) {_value = value;}
signals:
    void valueChanged (int);
private:
    int _value;
}

两个类有相同的内部状态,相同的公有方法,但后一个类却支持使用信号和槽的组件编程:这个类可以通过发射一个信号(valueChanged())来告诉
外界它的状态发生了变化,并且它有一个槽,可以接收信号。所有包含信号和槽的类都必须在它们的声明中提到Q_OBJECT。槽要由自己来实现,这里最好把
int setValue (int value)槽这样实现:
void UseSignalClass::setValue( int value )
{
    if ( value != _value ) {
        _val = value;
        emit valueChanged(value);
    }
}
emit valueChanged(value);这行代码是发射一个信号valueChanged。
要想使一个槽在一个信号被发射后被执行,要显示地进行连接:
UseSignalClass a,b;
connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));
这样做后,就把对象a的信号valueChanged和对象b的槽setValue连接了起来,当a的信号valueChanged被发射后,对象b的槽setValue马上就被执行。
执行以下这句代码:
b.setValue( 10 ); 
这句被执行后,对象b的valueChanged信号会被发射,但没有槽和该信号相连,所以什么也没做,信号被丢弃。
a.setValue( 80); 
这句被执行后,对象a的valueChanged信号会被发射,该信号有槽(对象b的setValue)相连,所以b.setValue(int)马上被执行,且参数为80,所以b.value()的值为80。
如果要解除已经建立好连接的信号和槽,可以使用disconnect()函数。bool QObject::disconnect ( const QObject * sender, const char * signal, 
  const Object * receiver, const char * member ) [static]
这个函数断开发射者中的信号和接收者中的槽函数之间的关联。有以下三种情况:
1、断开某个对象与其它对象的任何连接:
    disconnect(object, 0, 0, 0);或object->disconnect();
2、断开某个信号与其它任何槽的连接:
    disconnect(object, SIGNAL(signal()), 0, 0);或object->disconnect(SIGNAL(signal()));
3、断开两个对象之间的任何关联:
    disconnect(object, 0, receiver, 0);或object->disconnect(receiver);
在disconnect函数中0可以用作一个通配符,可分别表示任何信号、任何接收对象、接收对象中的任何槽函数。但是发射者不能为0,其它三个参数都可以为0。

键字signals指出随后开始信号的声明,这里signals用的是复数形式而非单数,siganls没有public、private、
protected等属性,这点不同于slots。另外,signals、slots关键字是QT自己定义的,不是C++中的关键字。
这个例子说明,采用QT的信号和槽机制后,对象之间可以在相互不知道的情况下一起工作,只要在最初的时候在他们中间建立了连接。
槽也是普通的C++函数,可以一样被调用,他唯一的特点就是 他们可以被信号连接。因为槽就是普通的成员函数,它们也和普通的成员函数一样有访问权限,一个槽的访问权限决定了哪些信号可以和它相连接,而信号就没有访问权限的概念。
一个public slots:区包含了任何信号都可以相连的槽。你生成了许多对象,它们互相并不知道,把它们的信号和槽连接起来,这样信息就可以正确地传递,并且就像一个铁路模型,把它打开然后让它跑起来。 
一个protected slots:区包含了之后这个类和它的子类的信号才能连接的槽。这就是说这些槽只是类的实现的一部分,而不是它和外界的接口。 
一个private slots:区包含了之后这个类本身的信号可以连接的槽。这就是说它和这个类是非常紧密的,甚至它的子类都没有获得连接权利这样的信任。 
也可以把槽定义为虚函数,这也很有用。
使用信号和槽机制,要注意以下问题:
1、信号和槽的机制是非常有效的,但是它不像“真正的”回调那样快。信号和槽稍微有些慢,这是因为它们所提供的灵活性。但这种损失相对来说是比较小的。但要追求高效率的话,比如在实时系统中就要尽量少用这种机制。
2、信号和槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时有可能形成死循环,所以,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射所接收到的同样的信号。
3、如果一个信号和多个槽相关联的话,那当这个信号被发射时,与之相关联的槽的执行顺序将是髓机的,且顺序不能指定。
4、宏定义不能用在signal和slot的参数中。
5、构造函数不能用在signals和slots声明区域内。
6、函数指针不能作为信号或槽的参数。
7、信号和槽不能有缺省参数值。
8、信号和槽不能携带模板类参数。
9、嵌套的类不能位于信号和槽区域内,也不能有信号或者槽。
10、友元声明不能位于信号和槽的声明区域内。