講稿(嵌入式設計與實現)
目 錄
第1章 嵌入式硬件開發(fā)環(huán)境 2
1.1 嵌入式系統(tǒng)的概念 2
1.2 熟悉OURS PXA270RP實驗箱的硬件環(huán)境 2
第2章 Linux常用命令 2
第3章 搭建嵌入式Linux開發(fā)環(huán)境 4
3.1 vwaretools的安裝與共享設置 4
3.2 tslib-1.4的編譯安裝 4
3.3 qtX11和qtE4的編譯安裝 5
3.4 PATH與LD_LIBRARY_PATH的設置 6
3.5 配置交叉編譯器 6
3.6 配置minicom、tftp和NFS 7
第4章bootloader、Linux內核及文件系統(tǒng)制作與移植 12
4.1 bootloader 12
4.2 Linux內核編譯與移植 12
4.3文件系統(tǒng)制作與移植 13
第5章 Qt圖形編程 14
5.1 嵌入式GUI簡介 14
5.2 Qt/Embedded開發(fā)入門 14
5.2.1 Qt/Embedded介紹 14
5.2.2 Qt/Embedded圖形界面 15
5.2.3 Qt/Embedded信號和槽機制 17
5.2.4 Qt/Embedded網絡編程 18
第6章 聊天系統(tǒng)設計與實現 18
6.1 聊天軟件需求分析 18
6.2 界面設計 18
6.3 網絡相關部分的實現 18
6.4 項目運行 24
第7章 系統(tǒng)移植與調試 24
第1章 嵌入式硬件開發(fā)環(huán)境
1.1 嵌入式系統(tǒng)的概念
以應用為中心,以計算機技術為基礎、軟硬件可裁剪、適應應用系統(tǒng)對功能、可靠性、成本、體積、功耗嚴格要求的專用計算機系統(tǒng)。開發(fā)機稱為宿主機,應用機稱為目標機。
1.2 熟悉OURS PXA270RP實驗箱的硬件環(huán)境
1、認識核心板和擴展板
2、認識nor flash、nand flash、sdram、ARM處理器
3、熟悉電源接口、并口、JTAG接口、串口、網口、USB接口
4、熟練掌握將PC機與開發(fā)實驗箱的連接
第2章 Linux常用命令
Shell與用戶間的關系如圖 2.1 所示。用戶在提示符下輸入的命令都由Shell 先解釋然后傳給 Linux 內核。
圖 2.1 內核、Shell 和用戶的關系
小知識:命令的使用可以通過man 命令名或命令名 -–help的方式獲得幫助。
1、ls: 列出目錄的內容,常用參數有-l(長文件名顯示格式)和-a(顯示所有文件), 顯示格式為:
文件類型與權限 鏈接數 文件屬主 文件屬組 文件大小 修改的時間 名字
2、find: 在指定目錄中搜索文件,常用參數為-name,如find /usr/qpe/pic/ -name *.png
3、cd: 改變工作目錄??墒褂谩癱d –”回到前次工作目錄?!?/”代表當前目錄,“../”代表上級目錄。
4、mkdir: 創(chuàng)建一個目錄,可以一次建立多個目錄,常用參數有-p(自動創(chuàng)建指定路徑中不存在的目錄),如mkdir /home/lny/myfile
5、rm: 刪除一個目錄中的一個或多個文件或目錄,常用參數-f(刪除已存在的目標文件而不提示),-i(在覆蓋目標文件前要求用戶確認),-r(遞歸地刪除該目錄及其子目錄下的所有內容)
6、cp: 將給出的文件或目錄復制到另一文件或目錄中,常用參數有-a(保留鏈接、文件屬性、并復制其子目錄),-f(同rm),-i(同rm)
7、mv: 為文件或目錄改名或將文件由一個目錄移入另一個目錄中,常用參數-f(同rm),-i(同rm)
8、ln: 為某一個文件在另外一個位置建立一個符號鏈接,常用參數-s(建立符號鏈接),如在當前目錄下創(chuàng)建/usr/qpe/lib/fonts的軟鏈接可以用命令
ln -s /usr/qpe/lib/fonts/ ./fonts
9、fdisk: 可以查看硬盤分區(qū)情況,并可對硬盤進行分區(qū)管理,如fdisk -l
10、mount:磁盤掛載命令。如掛載根目錄mount –o soft,timeo=100,rsize=1024 192.168.0.100:/ /mnt;
掛載U盤mount –t vfat /dev/sdb1 /mnt/usb
掛載windows目錄為mount -o username=administrator,password=pldy123,iocharset=utf8 //172.21.28.71/c /mnt/c
若想設置在開機時自動掛載,可在文件“/etc/fstab”中加入相應的設置行即可。
11、echo: 顯示字符串
12、export: 設置新的環(huán)境變量,如export QTDIR=/usr/local/Trolltech/Qt-4.4.3
export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
13、chmod: 改變文件的訪問權限. 文件的訪問權限可表示成:- rwx rwx rwx。在此設有三種不同的訪問權限:讀(r)、寫(w)和運行(x);三個不同的用戶級別:文件擁有者(u)、所屬的用戶組(g)和系統(tǒng)里的其他用戶(o)??稍黾右粋€用戶級別 a(all)來表示所有這三個不同的用戶級別。
① 對于第一種符號連接方式的 chmod 命令中,用加號“+”代表增加權限,用減號“?”刪除權限,等于號“=”設置權限,如chmod a+rx,u+w /home/lny/myfile
② 對于第二種八進制數指定的方式,將文件權限字符代表的有效位設為“1”,即“rw-”、“rw-”和“r--”的八進制表示為“110”、“110”、“100”,把這個 2 進制串轉換成對應的 8 進制數就是 6、6、4,也就是說該文件的權限為 664(三位八進制數),如chmod 765 /home/lny/myfile
14、tar: 對文件目錄進行打包或解包,常用參數有-c(建立新的打包文件),-f(對普通文件操作),-x(從打包文件中解出文件),-v(處理過程中輸出相關信息),-z(調用gzip來壓縮打包文件,與-x聯用時調用gzip完成解壓縮),-j(調用bzip2來壓縮打包文件,與-x聯用時調用bzip2完成解壓縮)。如tar -zcvf lny.tar.gz /home/lny; tar -jxvf linux-2.6.11.tar.bz2
第3章 搭建嵌入式Linux開發(fā)環(huán)境
3.1 vwaretools的安裝與共享設置
1、安裝VMware tools,以方便鼠標內外移動(確?!疤摂M化”不選),步驟如下:
VM菜單
→VMware tools install
→“是”
→將光驅(linux中的光驅)的VMware tools 中的Vmwaretools-6.0.2-59824.tar.gz復制到目錄root下
→在終端對Vmwaretools-6.0.2-59824.tar.gz進行解壓tar –zxvf Vmwaretools-6.0.2-59824.tar.gz
→cd vmware-tools-distrib
→./vmware-install.pl(全部選yes,注意有一個默認為[no]的選項改為yes)
2、設置windows與linux相互共享:
Windows下訪問linux的內容:
確保網線正確連接;
確保網絡端口激活(系統(tǒng)→管理→網絡→設置靜態(tài)IP并激活);
確保samba服務安裝并啟動(系統(tǒng)→管理→服務器設置→services中勾選smb選項);
添加samba用戶(必須是存在的用戶,如果沖突,則注釋/etc/samba/smbusers中對應的用戶名)(“首選項”→samba用戶→添加用戶);
添加共享(選擇共享目錄和設置共享對象權限等)。
通過\\192.168.11.7即“\\虛擬機ip”的形式訪問。
3、Linux下訪問windows的內容:
確保安裝時沒有選擇“虛擬化”選項;
菜單VM
→settings
→options
→shared folds
→add。
在linux系統(tǒng)下通過/mnt/hgfs目錄訪問windows中共享文件夾。
3.2 tslib-1.4的編譯安裝
假設源碼解壓目錄為: /home/tslib-1.4
1、cd /home/tslib-1.4
./autogen.sh //生成congigure
2、./configure --host=arm-linux --cache-file=arm-linux.cache//加上參數--prefix=/home/tslib-1.4可以看到頭文件
3、make
出現錯誤:undefined reference 'rpl_malloc'
解決:將config.h.in中的
#undef malloc 行注釋掉
重新執(zhí)行make,OK!
4、make install
生成的庫文件分別在目錄./src、./plugins的.lib目錄中,其中./lib為隱藏目錄,src/.lib中包含libts-0.0.so.0.1.1,libts-0.0.so.0、libts.la、libts.lai、libts.so,plugins/.lib中包含ucb1x00.so、pthres.so、linear.so、input.so、variance.so、dejitter.so等,庫文件版本為libts-0.0.so.0.1.1
5、拷貝
mkdir tslib-1.4
cd tslib-1.4
mkdir lib etc plugins include tests
目錄lib:將src/.lib/中的libts-0.0.so.0,libts-0.0.so.0.1.1,libts.so拷到其中。
目錄etc: 將etc/中的ts.conf拷到其中。//結合自己的觸摸屏型號進行相應的修改
目錄plugins: 將plugins/.libs/中的*.so拷到其中。//結合自己的觸摸屏型號,刪除部分庫文件
目錄tests: 將tests/中的ts_*拷到其中。//只需要保留ts_calibrate和ts_test
目錄include:將src/tslib.h拷到其中。
6、測試
執(zhí)行測試程序ts_calibrate時一直出現錯誤:ts_open:no such device
通過查找ts_calibrate.c發(fā)現,編譯時如果沒有加參數--enable-inputapi=no,則應將環(huán)境變量定義如下:
export TSLIB_TSDEVICE=/dev/input/event0(出錯時為TSLIB_TSDEVICE=/dev/touchscreen/ucb1x00,因為我的觸摸屏型號為 ucb1x00)
export TSLIBDIR=/home/tslib-1.4
export TSLIB_CONFFILE=$TSLIBDIR/etc/ts.conf
export TSLIB_PLUGINDIR=$TSLIBDIR/plugins
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_CONSOLEDEVICE=none
export POINTERCAL_FILE=/etc/pointercal //生成校準文件
export LD_LIBRARY_PATH=$TSLIBDIR/lib
export QWS_MOUSE_PROTO=TPanel:/dev/touchscreen/ucb1x00
export TSLIB_CALIBFILE=/etc/pointercal //應用校準文件
[ -f /etc/pointercal ] || /home/tslib-1.4/tests/ts_calibrate //檢查是否存在校準文件
另外,還要注意的是,ts.conf內容如下:
module_raw input
#module_raw ucb1x00 //如果注釋前一句而保留該句,則會出現意想不到的問題。
module pthres pmin=1
module variance delta=30
module dejitter delta=100
module linear
執(zhí)行ts_calibrate順利通過。
3.3 qtX11和qtE4的編譯安裝
一、QT-X11環(huán)境的配置
1、解壓qt-x11-4.4.3.tar.gz
2、cd 解壓了的目錄 QT-X11
3、 #./configure //生成Makefile
#make //要好幾個小時(約3個半小時)
#make install //安裝完后會生成目錄/usr/local/Trolltech/QT-4.4.3 ,這時剛才解壓完得到的QT-X11可以不要了。
4、設置環(huán)境變量(實際上是設置編譯環(huán)境):
在/etc/profile 加入:
#for QT-X11-4.4.3
export QTDIR=/usr/local/Trolltech/Qt-4.4.3
export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
export PATH=$QTDIR/bin:$PATH
export QMAKESPEC=$QTDIR/mkspecs/linux-g++
5、#source /etc/profile 使環(huán)境變量生效,確保要用的編譯器擺在首位,以屏蔽系統(tǒng)自帶的編譯器。
二、QT-embed環(huán)境的配置
1、把arm-linux-gcc版本:3.3.2 放目錄/usr/local/arm并在環(huán)境變量PATH中指明
#export PATH=/usr/local/arm/3.3.2/bin:$PATH
2、解壓qt-embedded-linux-4.4.3.tar.gz 得qt-embed
3、配置
支持觸摸屏的參數配置:
./configure -release -shared -fast -no-largefile -qt-sql-sqlite
-no-qt3support -no-xmlpatterns -no-mmx -no-3dnow -no-sse -no-sse2
-no-svg -no-webkit -qt-zlib -qt-gif -qt-libtiff -qt-libpng -qt-libmng
-qt-libjpeg -make libs -nomake tools -nomake examples -nomake docs
-nomake demo -no-nis -no-cups -no-iconv -no-dbus -no-openssl
-xplatform qws/linux-arm-g++ -embedded arm -little-endian -qt-freetype
-depths 16,18 -qt-gfx-linuxfb -no-gfx-transformed -no-gfx-multiscreen
-no-gfx-vnc -no-gfx-qvfb -qt-kbd-usb -no-glib -qt-mouse-tslib
-I/home/tslib-1.4/include -L/home/tslib-1.4/lib
4、#make
5、#make install
3.4 PATH與LD_LIBRARY_PATH的設置
參考3.3節(jié)內容。
3.5 配置交叉編譯器
修改/etc/profile,在有“pathmunge”命令語句處加上如下命令語句:
Pathmunge /usr/local/arm-linux/bin
3.6 配置minicom、tftp和NFS
1、配置minicom
開發(fā)板上的信息顯示給開發(fā)人員最常用的就是通過串口線輸出到宿主機的顯示器上,這樣,開發(fā)人員就可以看到系統(tǒng)的運行情況了。Minicom 是 Linux 下串口通信的軟件,它的使用完全依靠鍵盤的操作,雖然沒有“超級終端”那么易用,但是使用習慣之后讀者將會體會到它的高效與便利。下面主要講解如何對Minicom 進行串口參數的配置。
首先在命令行中鍵入“minicom”,這就啟動了 minicom 軟件。Minicom 在啟動時默認會進行初始化配置,如圖 3.1 所示。
圖 3.1 minicom 啟動
注意 在 Minicom 的使用中,經常會遇到三個鍵的操作,如“CTRL-A Z”,這表示先同時按下 CTRL和“A”(大寫),然后松開此二鍵再按下“Z”。
正如圖 3.1 中的提示,接下來可鍵入 CTRL+A Z,來查看 minicom 的幫助,如圖 3.2所示。按照幫助所示,可鍵入“O”(代表 Configure Minicom)來配置 minicom 的串口參數,當然也可以直接鍵入“CTRL-A O”來進行配置,如圖 3.3 所示。
圖3.2 minicom 幫助
圖 3.3 minicom 配置界面
在這個配置框中選擇“Serial port setup”子項,進入如圖 3.4 所示配置界面。上面列出的配置是 minicom 啟動是的默認配置,用戶可以通過鍵入每一項前的大寫字母,分別對每一項進行更改。圖 3.5 所示為在“Change which setting 中”鍵入了“A”,此時光標轉移到第 A 項的對應處。
注意 在 minicom 中“ttyS0”對應“COM1”,“ttyS1”對應“COM2”。
圖3.4 minicom 串口屬性配置界面
圖 3.5 minicom 串口號配置
接下來,要對波特率、數據位和停止位進行配置,鍵入“E”,進入如圖 3.6 所示的配置界面。
在該配置界面中,可以鍵入相應波特率、停止位等對應的字母,即可實現配置,配置完成后按回車鍵就退出了該配置界面,在上層界面中顯示如圖 3.7 所示配置信息,要注意與圖3.4 進行對比,確定相應參數是否已被重新配置。
圖 3.6 minicom 波特率等配置界面
圖 3.7 minicom 配置完成后界面
到此為止,讀者已經能將開發(fā)板的系統(tǒng)情況通過串口打印到宿主機上了,這樣,就能很好地了解硬件的運行狀況。
小知識 通過串口打印信息是一個很常見的手段,很多其他情況如路由器等也是通過配置串口的波特率這些參數來顯示對應信息的。
2、tftp
tftp 協(xié)議是簡單文件傳輸協(xié)議,它可以看作是一個 FTP 協(xié)議的簡化版本,與 FTP 協(xié)議相比,它的最大區(qū)別在于沒有用戶管理的功能。它的傳輸速度快,可以通過防火墻,使用方便快捷,因此在嵌入式的文件傳輸中廣泛使用。
tftp 分為客戶端和服務器端兩種。通常,首先在宿主機上開啟 tftp 服務器端服務,設置好 tftp 的根目錄內容(也就是供客戶端下載的文件),接著,在目標板上開啟 tftp的客戶端程序(現在很多開發(fā)板都已經提供了該項功能)。這樣,把目標板和宿主機用直連線相連之后,就可以通過 tftp 協(xié)議傳輸可執(zhí)行文件了。
Linux 下 tftp 的服務器服務是由 xinetd 所設定的,默認情況下是處于關閉狀態(tài)。首先,要修改 tftp 的配置文件,開啟 tftp 服務,如下所示:
[root@ateng tftpboot]# vi /etc/xinetd.d/tftp
# default: off
# description: The tftp server serves files using the trivial file transfer \
# protocol. The tftp protocol is often used to boot diskless \
# workstations, download configuration files to network-aware printers, \
# and to start the installation process for some operating systems.
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /tftpboot
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
在這里,主要要將“disable=yes”改為“no”,另外,從“server_args”可以看出,tftp服務器端的默認根目錄為“/tftpboot”,用戶若需要可以更改為其他目錄。接下來,重啟 xinetd 服務,使剛才的更改生效,如下所示:
[root@ateng tftpboot]# service xinetd restart
關閉 xinetd: [ 確定 ]
啟動 xinetd: [ 確定 ]
接著,使用命令“netstat -au”以確認 tftp 服務是否已經開啟,如下所示:
[root@ateng tftpboot]# netstat -au
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 0 0 *:32768 *:*
udp 0 0 *:831 *:*
udp 0 0 *:tftp *:*
udp 0 0 *:sunrpc *:*
udp 0 0 *:ipp *:*
這時,用戶就可以把所需要的傳輸文件放到“/tftpboot”目錄下,這樣,主機上的 tftp 服務就可以建立起來了。
接下來,用直連線(注意:不可以使用網線)把目標板和宿主機連起來,并且將其配置成一個網段的地址,再在目標板上啟動 tftp 客戶端程序(注意:不同的開發(fā)板所使用的命令可能會不同,讀者可以查看幫助來獲得確切的命令名及格式),如下所示:
=>tftpboot 0x30200000 zImage
TFTP from server 192.168.1.1; our IP address is 192.168.1.100
Filename 'zImage'.
Load address: 0x30200000
Loading: #################################################################
###############################################################
#############################################
done
Bytes transferred = 881988 (d7544 hex)
可以看到,此處目標板使用的 IP 為“192.168.1.100”,宿主機使用的 IP 為“192.168.1.1”,下載到目標板的地址為 0x30200000,文件名為“zImage”。
小知識 tftp 是一個很好的文件傳輸協(xié)議,它的簡單易用吸引了廣大用戶。但它同時也存在著較大的安全隱患。由于 tftp 不需要用戶的身份認證,因此給了黑客的可乘之機。因此在使用 tftp 時一定要設置一個單獨的目錄作為 tftp 服務的根目錄,如上文所述的“/tftpboot”等。
3、NFS
在/etc/exports中加入語句:
/ 192.168.0.* (rw,inscure,no_root_squash,no_all_squash)
第4章bootloader、Linux內核及文件系統(tǒng)制作與移植
4.1 bootloader
1、編譯
cd /pxa270_linux/blob_ours/blob-xscale
make –f Makefile.cvs
./configure –host=arm-linux –with-board=mainstone –with-linux-prefix=/pxa270_linux/linux/ --enable-xli –enable-network
make(保存在/pxa270_linux/blob_ours/blob-xscale/src/blob下)
2、移植(確保開發(fā)板上電)
cd /pxa270_linux/tools
./Jflashmm-linux PXA270 blob p(該命令是尋找PXA270.dat文件所指定的CPU,把blob文件燒寫到這個CPU使用的flash中,要求blob,PXA270.dat與Jflashmm-linux在同一個文件夾中,.dat文件不可以加后綴。
4.2 Linux內核編譯與移植
1、編譯
內核的編譯根據不同的情況會有不同的步驟,但其中最主要分別為3 個步驟:內核配置、建立依存關系、建立內核,其他的為一些輔助功能,如清除文件等。
(1)內核配置
cd /pxa270_linux/linux
make menuconfig (菜單式配制)
在menuconfig 的配置界面是圖形化的內核裁減界面。通過此部分,讀者可以方便地選擇,決定哪些部分被加載并編譯入Linux內核,哪些部分被編譯為模塊,哪些部分不用,如圖 4.1 所示?!癓oad an Alternate Configuration File”選項表示裝載一個已經保存好的設置。也可以選擇“Save Configuration to an Alternate File”選項保存自己的配置文件。
圖 4.1 make menuconfig 配置界面
此外,要注意 2.6 和 2.4 內核在串口命名上的一個重要區(qū)別,在 2.4 內核中“COM1”對應的是“ttyS0”,而在 2.6 內核中“COM1”對應“ttySAC0”,因此在啟動參數的子項要格外注意,如圖4.3 所示,否則串口打印不出信息。
(2)建立依賴關系
make dep
由于內核源碼樹中的大多數文件都與一些頭文件有依賴關系,因此要順利建立內核,內核源碼樹中的每個 Makefile 就必須知道這些依賴關系。建立依賴關系往往發(fā)生在第一次編譯內核的時候,它會在內核源碼樹中每個子目錄產生一個“.depend”文件。
(3)建立內核
make clean
make zImage
這里建立的為壓縮的內核映像,名為zImage,位于/pxa270_linux/linux/arch/arm/boot目錄中。
2、移植
cp zImage /tftpboot –rf (虛擬機終端)
以下命令在minicom中完成:
blob>tftp zImage –kernel (下載到內存0xa0008000處)
blob>fwrite 0xa0008000 0x00040000 0x00200000
表示從內存0xa0008000處取出長度為0x00200000的數據,寫入flash中0x00040000開始的地址中。
4.3文件系統(tǒng)制作與移植
1、制作文件系統(tǒng):
cd /pxa270_linux/fs
./mkfs.jffs2 –r rootfs270 –o xscale_fs.jffs2 –e 0x40000 –pad=0x01000000(根文件系統(tǒng))
./mkfs.jffs2 –r junk –o junk.jffs2 –e 0x40000 –pad=0x0dc0000(擴展文件系統(tǒng))
其中,-r后面是指令要做成image的文件夾,默認為當前文件夾;-o后面是指令輸出的文件名,-e表擦除塊的大小,默認為64KB,--pad表輸出文件的大小,為了不浪費flash空間,這個值最好符合flash driver所規(guī)劃的區(qū)塊大小,如果不足,則使用0xff來填充補滿。
2、文件系統(tǒng)移植:
cp xscale_fs.jffs2 /tftpboot –rf (虛擬機終端)
cp junk.jffs2 /tftpboot –rf (虛擬機終端)
以下命令在minicom中完成:
blob>tftp xscale_fs.jffs2
blob>fwrite 0xa1000000 0x00240000 0x01000000
blob>tftp junk .jffs2
blob>fwrite 0xa1000000 0x01240000 0x0dc0000
表示從內存0xa1000000處取出長度為0x0dc0000的數據,寫入flash中0x01240000開始的地址中。
第5章 Qt圖形編程
5.1 嵌入式GUI簡介
GUI( 圖形用戶界面)是指計算機與其使用者之間的對話接口,它的存在為使用者提供了友好便利的界面,并大大方便了非專業(yè)用戶的使用,使得人們從煩瑣的命令中解脫出來,可以通過窗口、菜單方便地進行操作。
Qt/Embedded是Trolltech(奇趣)公司為嵌入式系統(tǒng)開發(fā)的Qt版本。從Qt 4.1版本開始,Qt/Embedded改名為Qtopia Core,又從Qt 4.4.1版本開始,又改名為Qt for Embedded Linux。其優(yōu)點是:
1、以開發(fā)包的形式提供,包括了圖形設計器、Makefile制作工具、字體國際化工具、Qt的C++類庫等。
2、支持跨平臺(如Microsoft Windows、MacOS X、Linux、Solaris等)。
3、類庫支持跨平臺(封裝了適應不同操作系統(tǒng)的訪問細節(jié))。
4、模塊化,可任意裁減(最小可裁減到幾百KB,但這時已基本失去了使用價值)。
缺點是:結構過于復雜臃腫,很難進行底層的擴充、定制和移植。
5.2 Qt/Embedded開發(fā)入門
5.2.1 Qt/Embedded介紹
1、架構如下圖所示。
應用程序源代碼
Qt API
Qt/Embedded
Qt/X11
Qt/XLib
X Windows Server
幀緩沖
Linux內核
Qt/Embedded與Qt/X11的Linux版本的比較
2、Qt的開發(fā)環(huán)境
Qt桌面版本:Qt/X11或Qt/Windows,結合大家熟知的Visual C++或Borland C++就可以進行開發(fā)了。`
3、Qt的支撐工具
Qmake和Qt designer(圖形設計器)
5.2.2 Qt/Embedded圖形界面
Qt提供了一整套的窗口部件,它們組合起來可用于創(chuàng)建用戶界面的可視元素。窗口部件是QWidget或其子類的實例,用戶自定義的窗口通過子類化得到,如下圖所示。
QObject
QTimer
QWidget
QDialog
QFrame
QSpinBox
QLabel
QLineEdit
對于初學者來說,使用designer工具設計程序界面非常方便快捷,如秒表程序stopwatch的界面文件digclock.ui效果如下圖所示。
播放器程序mediaplayer界面文件videoface.ui效果如下圖所示。
對應的.h文件代碼自動生成,但比較復雜,為了熟悉代碼,完全可以用代碼的形式生成用戶界面,如通訊錄程序addressbook中的部分代碼如下:
addressBook::addressBook(QWidget *parent)
{
setWindowTitle(tr("this is addressbook."));
setFixedSize(lcdWidth,lcdHeight);
contacts=new QMap<QString,QString>;
saveBt=new QPushButton(tr("save")) ;
cancelBt=new QPushButton(tr("cancel"));
findBt=new QPushButton(tr("find"));
contactName=new QLabel(tr("name"));
contactTele=new QLabel(tr("telephone"));
nameDetail=new QLineEdit;
teleNo=new QTextEdit ;
QHBoxLayout *hlayout=new QHBoxLayout;
hlayout->addWidget(saveBt,Qt::AlignCenter);
hlayout->addWidget(cancelBt,Qt::AlignJustify);
hlayout->addWidget(findBt,Qt::AlignCenter);
QGridLayout *layout=new QGridLayout;
layout->addWidget(contactName,0,0,Qt::AlignRight);
layout->addWidget(nameDetail,0,1);
layout->addWidget(contactTele,1,0,Qt::AlignTop);
layout->addWidget(teleNo,1,1,Qt::AlignLeft);
layout->addLayout(hlayout,2,1);
setLayout(layout);
connect(saveBt,SIGNAL(clicked()),this,SLOT(saveInform()));
connect(cancelBt,SIGNAL(clicked()),this,SLOT(cancelInform()));
connect(findBt,SIGNAL(clicked()),this,SLOT(findName()));
}
5.2.3 Qt/Embedded信號和槽機制
1、機制概述
信號(signals)和槽機制是Qt的核心機制,是Qt自行定義的一種通信機制,獨立于標準的C/C++語言。所有從QObject或其子類(如QWidget)派生的類都能夠包含信號和槽。當對象改變狀態(tài)時,信號就由該對象發(fā)射(Emit)出去了,它不知道另一端是是誰在接收這個信號。槽函數用于接收信號,它們是普通的對象成員函數,一個槽函數并不知道是否有任何信號與自己相連接。
對象間信號與插槽的關系
用戶可以將多個信號與單個槽函數連接,也可以將單個信號與多個槽函數連接,甚至將一個信號與另外一個信號相連接。其間的關系如下圖所示。
對象2
信號1
槽1
槽2
對象1
信號1
信號2
對象3
槽1
槽2
2、信號與插槽實現
信號的定義:
signals:
void mySignal();
void mySignal(int x);
void mySignalParam(int x,int y);
槽函數的定義:
public slots:
void mySlot();
void mySlot(int x);
void mySlotParam(int x,int y);
信號與插槽關聯(通過QObject對象的connect()函數實現)
QLabel *label=new QLabel;
QScrollBar *scroll=new QScrollBar;
QObject::connect(scroll,SIGNAL(valueChanged(int)),label,SLOT(setNum(int)));
5.2.4 Qt/Embedded網絡編程
QTcpSocket和QTcpServer類,具體查看Qt的幫助文檔。
第6章 聊天系統(tǒng)設計與實現
6.1 聊天系統(tǒng)需求分析
1、使用對象:09計嵌。
2、系統(tǒng)說明:以宿舍為單位,主界面中的成員為全班同學,聊天包括私聊、群聊(信息僅限于本宿成員)和廣播(全班同學都能看到);ID為各自的學號,禁止非本班同學登錄。
3、功能分析:注冊、登錄、下線、加入群、退出群、添加和修改個人信息、聊天、提供對用戶信息和聊天信息的保存等。
6.2 界面設計
服務器端創(chuàng)建聊天室 客戶端登錄界面
6.3 網絡相關部分的實現
服務器端程序部分代碼:
TcpServer::TcpServer(QWidget *parent,Qt::WindowFlags f)
:QDialog(parent,f)
{
setWindowTitle(tr("TCP Server"));
QVBoxLayout *vbMain=new QVBoxLayout(this);
ListWidgetContent=new QListWidget(this);
vbMain->addWidget(ListWidgetContent);
QHBoxLayout *hb=new QHBoxLayout();
LabelPort=new QLabel(this);
LabelPort->setText(tr("Port"));
hb->addWidget(LabelPort);
LineEditPort=new QLineEdit(this);
hb->addWidget(LineEditPort);
vbMain->addLayout(hb);
PushButtonCreate=new QPushButton(this);
PushButtonCreate->setText(tr("create"));
vbMain->addWidget(PushButtonCreate);
connect(PushButtonCreate,SIGNAL(clicked()),this,SLOT(slotCreateServer()));
port=8010;
LineEditPort->setText(QString::number(port));
}
TcpServer::~TcpServer()
{
}
void TcpServer::slotCreateServer()
{
server=new Server(this,port);
connect(server,SIGNAL(updateServer(QString,int)),
this,SLOT(updateServer(QString,int)));
PushButtonCreate->setEnabled(false);
}
void TcpServer::updateServer(QString msg,int length)
{
ListWidgetContent->addItem(msg.left(length));
}
TcpClientSocket::TcpClientSocket(QObject *parent)
{
connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived()));
connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));
}
void TcpClientSocket::dataReceived()
{
while(bytesAvailable()>0)
{
char buf[1024];
int length=bytesAvailable();
read(buf,length);
QString msg=buf;
emit updateClients(msg,length);
}
}
TcpClientSocket::~TcpClientSocket()
{
}
void TcpClientSocket::slotDisconnected()
{
this->close();
emit disconnected(this->socketDescriptor());
}
Server::Server(QObject *parent,int port)
:QTcpServer(parent)
{
listen(QHostAddress::Any,port);
}
void Server::incomingConnection(int socketDescriptor)
{
TcpClientSocket *tcpClientSocket=new TcpClientSocket(this);
connect(tcpClientSocket,SIGNAL(updateClients(QString,int)),
this,SLOT(updateClients(QString,int)));
connect(tcpClientSocket,SIGNAL(disconnected(int)),
this,SLOT(slotDisconnected(int)));
tcpClientSocket->setSocketDescriptor(socketDescriptor);
tcpClientSocketList.append(tcpClientSocket);
}
void Server::updateClients(QString msg,int length)
{
emit updateServer(msg,length);
for(int i=0;i<tcpClientSocketList.count();i++)
{
QTcpSocket *item=tcpClientSocketList.at(i);
if(item->write(msg.toLatin1(),length)!=length)
continue;
}
}
void Server::slotDisconnected(int descriptor)
{
for(int i=0;i<tcpClientSocketList.count();i++)
{
QTcpSocket *item=tcpClientSocketList.at(i);
if(item->socketDescriptor()==descriptor)
{
tcpClientSocketList.removeAt(i);
return;
}
}
return;
}
客戶端程序部分代碼:
TcpClient::TcpClient(QDialog *parent,Qt::WindowFlags f)
:QDialog(parent,f),status(false),port(8010)
{
setWindowTitle(tr("TCP client"));
ListWidgetContent=new QListWidget;
LineEditMsg=new QLineEdit;
PushButtonSend=new QPushButton(tr("send"));
PushButtonSend->setEnabled(false);
QHBoxLayout *msgLayout=new QHBoxLayout;
msgLayout->addWidget(LineEditMsg);
msgLayout->addWidget(PushButtonSend);
QHBoxLayout *userLayout=new QHBoxLayout;
userNameLabel=new QLabel(tr("user name:"));
LineEditUser=new QLineEdit;
userLayout->addWidget(userNameLabel);
userLayout->addWidget(LineEditUser);
QHBoxLayout *serverIPLayout=new QHBoxLayout;
serverIPLabel=new QLabel(tr("server IP:"));
LineEditServerIP=new QLineEdit;
serverIPLayout->addWidget(serverIPLabel);
serverIPLayout->addWidget(LineEditServerIP);
QHBoxLayout *portLayout=new QHBoxLayout;
portLabel=new QLabel(tr("port Num:"));
LineEditPort=new QLineEdit;
LineEditPort->setText(QString::number(port));
portLayout->addWidget(portLabel);
portLayout->addWidget(LineEditPort);
PushButtonEnter=new QPushButton(tr("enter"));
QVBoxLayout *mainlayout=new QVBoxLayout;
mainlayout->addWidget(ListWidgetContent);
mainlayout->addLayo