?
12.3??實(shí)驗(yàn)內(nèi)容——使用Qt編寫“Hello,World”程序
1.實(shí)驗(yàn)?zāi)康?/h4>
通過編寫一個跳動的“Hello,World”字符串,進(jìn)一步熟悉嵌入式Qt的開發(fā)過程。
2.實(shí)驗(yàn)步驟
(1)生成一個工程文件(.pro文件)。
使用命令progen產(chǎn)生一個工程文件(progen程序可在tmake的安裝路徑下找到)。
如下所示:
progen?–t?app.t?–o?hello.pro
那樣產(chǎn)生的hello.pro工程文件并不完整,開發(fā)者還需添加工程所包含的頭文件,源文件等信息。
(2)新建一個窗體。
啟動Qt圖形編輯器,使用如下命令:
./designer(該程序在qt-2.3.x?for?x11的安裝路徑的bin目錄下)
接著單擊編輯器的“new”菜單,彈出了一個“new?Form”對話框,在這個對話框里選擇“Widget”,然后單擊“OK”按鈕,這樣就新建了一個窗體。
接下來再對這個窗體的屬性進(jìn)行設(shè)置,注意把窗體的“name”屬性設(shè)為“Hello”;窗體的各種尺寸設(shè)為寬“240”、高“320”,目的是使窗體大小和FS2410帶的顯示屏的大小一致;窗體背景顏色設(shè)置為白色。具體設(shè)置如圖12.18所示。
圖12.18??Hello窗體的屬性設(shè)置
設(shè)置完成后,將其保存為hello.ui文件,這個文件就是Hello窗體的界面存儲文件。
(3)生成Hello窗體類的頭文件和實(shí)現(xiàn)文件。
下面根據(jù)上述的界面文件hello.ui使用uic工具產(chǎn)生Hello窗體類的頭文件和實(shí)現(xiàn)文件,具體方法是:
$?cd?qt-2.3.7/bin
$?uic?–o?hello.h?hello.ui
$?uic?–o?hello.cpp?–impl?hello.h?hello.ui
這樣就得到了Hello窗體類的頭文件hello.h和實(shí)現(xiàn)文件hello.cpp。下面就可以根據(jù)需要實(shí)現(xiàn)的具體功能,在hello.cpp文件里添加相應(yīng)的代碼。
比如要在Hello的窗體上顯示一個動態(tài)的字符串“Hello,World”,那么需要重新實(shí)現(xiàn)paintEvent(QPaintEvent?*)方法,同時還需要添加一個定時器QTimer實(shí)例,以周期性刷新屏幕,從而得到動畫的效果。下面是修改后的hello.h和hello.cpp文件。
?
/****************************************************************************
**?以下是?hello.h?的代碼
****************************************************************************/
#ifndef?HELLO_H
#define?HELLO_H
#include?<qvariant.h>
#include?<qwidget.h>
class?QVBoxLayout;
class?QHBoxLayout;
class?QGridLayout;
class?Hello?:?public?QWidget
{
Q_OBJECT
public:
????Hello(QWidget*?parent?=?0,?const?char*?name?=?0,?WFlags?fl?=?0);
????~Hello();
/*?以下是手動添加的代碼?*/
signals:
????void?clicked();
protected:
????void?mouseReleaseEvent(QMouseEvent?*);
????void?paintEvent(QPaintEvent?*);
private?slots:
????void?animate();
private:
????QString?t;
????int?b;
};
#endif?//?HELLO_H
/****************************************************************************
**?以下是?hello.cpp?源代碼
****************************************************************************/
#include?"hello.h"
#include?<qlayout.h>
#include?<qvariant.h>
#include?<qtooltip.h>
#include?<qwhatsthis.h>
#include?<qpushbutton.h>
#include?<qtimer.h>
#include?<qpainter.h>
#include?<qpixmap.h>
/*
*?Constructs?a?Hello?which?is?a?child?of?'parent',?with?the
*?name?'name'?and?widget?flags?set?to?'f'
*/
Hello::Hello(QWidget*?parent,?const?char*?name,?WFlags?fl)
:?QWidget(parent,?name,?fl)
{
????if?(!name)
?????????setName("Hello");
????resize(240,?320);
????setMinimumSize(QSize(240,?320));
????setMaximumSize(QSize(240,?320));
????setSizeIncrement(QSize(240,?320));
????setBaseSize(QSize(240,?320));
????QPalette?pal;
????QColorGroup?cg;
????cg.setColor(QColorGroup::Foreground,?black);
????cg.setColor(QColorGroup::Button,?QColor(192,?192,?192));
????cg.setColor(QColorGroup::Light,?white);
????cg.setColor(QColorGroup::Midlight,?QColor(223,?223,?223));
????cg.setColor(QColorGroup::Dark,?QColor(96,?96,?96));
????cg.setColor(QColorGroup::Mid,?QColor(128,?128,?128));
????cg.setColor(QColorGroup::Text,?black);
????cg.setColor(QColorGroup::BrightText,?white);
????cg.setColor(QColorGroup::ButtonText,?black);
????cg.setColor(QColorGroup::Base,?white);
????cg.setColor(QColorGroup::Background,?white);
????cg.setColor(QColorGroup::Shadow,?black);
????cg.setColor(QColorGroup::Highlight,?black);
????cg.setColor(QColorGroup::HighlightedText,?white);
????pal.setActive(cg);
????cg.setColor(QColorGroup::Foreground,?black);
????cg.setColor(QColorGroup::Button,?QColor(192,?192,?192));
????cg.setColor(QColorGroup::Light,?white);
????cg.setColor(QColorGroup::Midlight,?QColor(220,?220,?220));
????cg.setColor(QColorGroup::Dark,?QColor(96,?96,?96));
????cg.setColor(QColorGroup::Mid,?QColor(128,?128,?128));
????cg.setColor(QColorGroup::Text,?black);
????cg.setColor(QColorGroup::BrightText,?white);
????cg.setColor(QColorGroup::ButtonText,?black);
????cg.setColor(QColorGroup::Base,?white);
????cg.setColor(QColorGroup::Background,?white);
????cg.setColor(QColorGroup::Shadow,?black);
????cg.setColor(QColorGroup::Highlight,?black);
????cg.setColor(QColorGroup::HighlightedText,?white);
????pal.setInactive(cg);
????cg.setColor(QColorGroup::Foreground,?QColor(128,?128,?128));
????cg.setColor(QColorGroup::Button,?QColor(192,?192,?192));
????cg.setColor(QColorGroup::Light,?white);
????cg.setColor(QColorGroup::Midlight,?QColor(220,?220,?220));
????cg.setColor(QColorGroup::Dark,?QColor(96,?96,?96));
????cg.setColor(QColorGroup::Mid,?QColor(128,?128,?128));
????cg.setColor(QColorGroup::Text,?black);
????cg.setColor(QColorGroup::BrightText,?white);
????cg.setColor(QColorGroup::ButtonText,?QColor(128,?128,?128));
????cg.setColor(QColorGroup::Base,?white);
????cg.setColor(QColorGroup::Background,?white);
????cg.setColor(QColorGroup::Shadow,?black);
????cg.setColor(QColorGroup::Highlight,?black);
????cg.setColor(QColorGroup::HighlightedText,?white);
????pal.setDisabled(cg);
????setPalette(pal);
????QFont?f(font());
????f.setFamily("adobe-helvetica");
????f.setPointSize(29);
????f.setBold(TRUE);
????setFont(f);
????setCaption(tr(""));
????
????/*?以下是手動添加的代碼?*/
????t?=?"Hello,World";
????b?=?0;
????QTimer?*timer?=?new?QTimer(this);
????connect(timer,?SIGNAL(timeout()),?SLOT(animate()));
????timer->start(40);
}
/*
*?Destroys?the?object?and?frees?any?allocated?resources
*/
Hello::~Hello()
{
}
/*?以下至結(jié)尾是手動添加的代碼?*/
void?Hello::animate()
{
????b?=?(b?+?1)?&?15;
????repaint(FALSE);
}
/*
Handles?mouse?button?release?events?for?the?Hello?widget.
We?emit?the?clicked()?signal?when?the?mouse?is?released?inside
the?widget.
*/
void?Hello::mouseReleaseEvent(QMouseEvent?*e)
{
????if?(rect().contains(e->pos()))
????emit?clicked();
}
/*?Handles?paint?events?for?the?Hello?widget.
Flicker-free?update.?The?text?is?first?drawn?in?the?pixmap?and?the
pixmap?is?then?blt'ed?to?the?screen.
*/
void?Hello::paintEvent(QPaintEvent?*)
{
????static?int?sin_tbl[16]?=?{0,?38,?71,?92,?100,?92,?
71,?38,?0,?-38,?-71,?-92,?-100,?-92,?-71,?-38};
????if?(t.isEmpty())
?????????eturn;
????/*?1:?Compute?some?sizes,?positions?etc.?*/
????QFontMetrics?fm?=?fontMetrics();
????int?w?=?fm.width(t)?+?20;
????int?h?=?fm.height()?*?2;
????int?pmx?=?width()/2?-?w/2;
????int?pmy?=?height()/2?-?h/2;
????/*?2:?Create?the?pixmap?and?fill?it?with?the?widget's?background?*/
????QPixmap?pm(w,?h);
????pm.fill(this,?pmx,?pmy);
????/*?3:?Paint?the?pixmap.?Cool?wave?effect?*/
????QPainter?p;
????int?x?=?10;
????int?y?=?h/2?+?fm.descent();
????int?i?=?0;
????p.begin(&pm);
????p.setFont(font());
????while?(!t[i].isNull())?
????{
?????????nt?i16?=?(b+i)?&?15;
?????????.setPen(QColor((15-i16)*16,255,255,QColor::Hsv));
?????????wText(x,?y-sin_tbl[i16]*h/800,?t.mid(i,1),?1);
??????????+=?fm.width(t[i]);
??????????+;
????}
????p.end();
????/*?4:?Copy?the?pixmap?to?the?Hello?widget?*/
????bitBlt(this,?pmx,?pmy,?&pm);
}
?
(4)編寫主函數(shù)main()。
一個Qt/Embeded應(yīng)用程序應(yīng)該包含一個主函數(shù),主函數(shù)所在的文件名是main.cpp。主函數(shù)是應(yīng)用程序執(zhí)行的入口點(diǎn)。以下是“Hello,World”例子的主函數(shù)文件main.cpp的實(shí)現(xiàn)代碼:
/****************************************************************************
**?以下是?main.cpp?源代碼
****************************************************************************/
#include?"hello.h"
#include?<qapplication.h>
/*
The?program?starts?here.?It?parses?the?command?line?and?builds?a?message
string?to?be?displayed?by?the?Hello?widget.
*/
#define?QT_NO_WIZARD
int?main(int?argc,?char?**argv)
{
????QApplication?a(argc,argv);
????Hello?dlg;
????QObject::connect(&dlg,?SIGNAL(clicked()),?&a,?SLOT(quit()));
????a.setMainWidget(&dlg);
????dlg.show();
????return?a.exec();
}
(5)編輯工程文件hello.pro文件。
到目前為止,為Hello,World例子編寫了一個頭文件和兩個源文件,這3個文件應(yīng)該被包括在工程文件中,因此還需要編輯hello.pro文件,加入hello.h、hello.cpp、main.cpp這3個文件名。具體定義如下:
/****************************************************************************
**?以下是?hello.pro?文件的內(nèi)容
****************************************************************************/
TEMPLATE?=?app
CONFIG?=?qt?warn_on?release
HEADERS?=?hello.h
SOURCES?=?hello.cpp?
????????????main.cpp
INTERFACES?=
(6)生成Makefile文件。
編譯器是根據(jù)Makefile文件內(nèi)容來進(jìn)行編譯的,所以需要生成Makefile文件。Qt提供的tmake工具可以幫助我們從一個工程文件(.pro文件)中產(chǎn)生Makefile文件。結(jié)合當(dāng)前例子,要從hello.pro生成一個Makefile文件的做法是首先查看環(huán)境變量$TMAKEPATH是否指向ARM編譯器的配置目錄,在命令行下輸入以下命令:
ECHO?$TMAKEPATH
如果返回的結(jié)果末尾不是…/qws/linux-arm-g++的字符串,那么需要把環(huán)境變量$TMAKEPATH所指的目錄設(shè)置為指向arm編譯器的配置目錄,過程如下:
EXPORT?TMAKEPATH?=?/TMAKE?安裝路徑/QWS/LINUX-ARM-G++
同時,應(yīng)確保當(dāng)前的QTDIR環(huán)境變量指向Qt/Embedded的安裝路徑,如果不是,則需要執(zhí)行以下過程。
EXPORT?QTDIR?=?……/qt-2.3.7
上述步驟完成后,就可以使用tmake生成Makefile文件,具體做法是在命令行輸入以下命令:
TMAKE?–O?MAKEFILE?HELLO.PRO
這樣就可以看到當(dāng)前目錄下新生成了一個名為Makefile的文件。下一步,需要打開這個文件,做一些小的修改。
①?將LINK?=?arm-linux-gcc改為:LINK?=?arm-linux-g++
這樣做是因?yàn)橐胊rm-linux-g++進(jìn)行鏈接。
②?將LIBS?=?$(SUBLIBS)?-L$(QTDIR)/lib?-lm?–lqte改為:
LIBS?=?$(SUBLIBS)?-L/usr/local/arm/2.95.3/lib?-L$(QTDIR)/lib?-lm?–lqte
這是因?yàn)殒溄訒r要用到交叉編譯工具toolchain的庫。
(7)編譯鏈接整個工程。
最后就可以在命令行下輸入make命令對整個工程進(jìn)行編譯鏈接了。
make生成的二進(jìn)制文件hello就是可以在FS2410上運(yùn)行的可執(zhí)行文件。