摘 要:在嵌入式PC/104選用的操作系統(tǒng)中,建立圖形界面的人機(jī)接口軟件在實(shí)際中有很大的意義,本文針對相關(guān)工業(yè)控制項(xiàng)目,討論了有關(guān)基于消息處理機(jī)制的圖形界面人機(jī)接口的建立方法和相關(guān)問題。
Abstract: Establishing Graphics User Interface software used on PC/104 is significant in the real industry project. This article discussed the method and problem of designing GUI based on message handling mechanism.
關(guān)鍵詞:圖形界面;操作系統(tǒng);控制系統(tǒng)
Keywords: Graphic User Interface. OS. Control System
1 引言
在新興的嵌入式PC/104應(yīng)用領(lǐng)域,因其硬件的獨(dú)特特點(diǎn),往往要求使用者的軟件操作系統(tǒng)要具備以下特點(diǎn):
● 操作系統(tǒng)占用空間小,大約占用幾M或十幾M;
● 系統(tǒng)穩(wěn)定性好;
● 對硬件配置要求低;
● 軟件開發(fā)靈活性高;
● 可以直接對硬件操作,控制響應(yīng)速度快。
基于這樣操作系統(tǒng)的軟件有時(shí)又要求為用戶提供一個(gè)良好的人機(jī)界面,而這類操作系統(tǒng)往往在圖形界面的能力上與Windows相比有著明顯的不足,針對這一難點(diǎn),本人在基于注塑機(jī)械手控制軟件的圖形界面開發(fā)上,進(jìn)行了積極的探索,希望對相關(guān)的軟件開發(fā)有所幫助。
建立與用戶交互的圖形界面,除了要在系統(tǒng)上畫出圖形外(這類系統(tǒng)往往提供繪畫函數(shù)),最關(guān)鍵的是要在圖形上建立軟件對用戶操作的響應(yīng),即類以于Windows系統(tǒng)中,系統(tǒng)針對用戶對圖形上的各種功能圖案(如按鈕)的點(diǎn)擊要給予響應(yīng)。所以建立圖形界面關(guān)鍵是要在用戶與軟件之間建立起一種交互機(jī)制,針對這一問題,本文以下部分將詳細(xì)進(jìn)行討論。
2 事件控制機(jī)制
軟件程序有兩種基本控制機(jī)制,即順序驅(qū)動(dòng)(或過程驅(qū)動(dòng))機(jī)制和事件控制機(jī)制,采用順序驅(qū)動(dòng)機(jī)制設(shè)計(jì)的程序有一個(gè)明顯的開始、明顯的過程和明顯的結(jié)束,這樣的控制機(jī)制不利于建立友好的人機(jī)接口。還有一種程序控制的機(jī)制,即事件驅(qū)動(dòng)機(jī)制,采用事件驅(qū)動(dòng)機(jī)制設(shè)計(jì)的程序,由事件的發(fā)生來控制。這樣的程序控制機(jī)制能夠?yàn)橛脩籼峁└玫娜藱C(jī)接口。
采用事件驅(qū)動(dòng)機(jī)制在人機(jī)交互很強(qiáng)的程序設(shè)計(jì)中比較適用,它給用戶在程序的運(yùn)行上以選擇的余地。事件驅(qū)動(dòng)控制機(jī)制多在基于Windows的軟件上使用,Windows上的軟件開發(fā)大多使用VC、VB等一些可視化開發(fā)平臺(tái),這些平臺(tái)往往已經(jīng)為用戶提供了事件驅(qū)動(dòng)機(jī)制,用戶只需設(shè)計(jì)相關(guān)事件處理程序,在程序編制過程中并不涉及事件驅(qū)動(dòng)機(jī)制的內(nèi)部運(yùn)行機(jī)理。而在本文所討論的開發(fā)環(huán)境下,必須自己搭建事件驅(qū)動(dòng)機(jī)制平臺(tái),在這一點(diǎn)上增加了程序設(shè)計(jì)的難度和復(fù)雜性。
采用事件驅(qū)動(dòng)機(jī)制可以大大減少消息丟失的可能性,如當(dāng)程序正在處理某一個(gè)消息時(shí),又產(chǎn)生了新的消息,這時(shí)事件驅(qū)動(dòng)機(jī)制會(huì)將新消息放入消息循環(huán)隊(duì)列,等到當(dāng)前消息處理完后再處理新來的消息,從而防止了消息丟失的可能。這種程序控制方式非常適用于系統(tǒng)及時(shí)響應(yīng)用戶的請求,與用戶建立友好的人機(jī)接口。這比采用順序驅(qū)動(dòng)機(jī)制設(shè)計(jì)的程序?qū)τ脩魜碚f更友好。
3 搭建事件驅(qū)動(dòng)機(jī)制平臺(tái)
在用戶界面設(shè)計(jì)中,事件就是用戶通過各種輸入設(shè)備進(jìn)行操作時(shí)所產(chǎn)生的各種信號,又稱消息。該消息是一種激發(fā)性的用于聯(lián)系用戶、計(jì)算機(jī)系統(tǒng)以及應(yīng)用軟件之間交互活動(dòng)的最基本信號。比如,用戶按下鍵盤上的某個(gè)鍵就可以形成一個(gè)消息,因?yàn)橛脩舻倪@一行為會(huì)對系統(tǒng)產(chǎn)生一個(gè)激發(fā)性的信號,使得系統(tǒng)由原來的某種狀態(tài)轉(zhuǎn)為另一種狀態(tài)。
消息的產(chǎn)生方式很多,主要由用戶通過按下鍵盤上的某個(gè)鍵或移動(dòng)鼠標(biāo)器并按下其上的某個(gè)鍵來產(chǎn)生。對于消息的產(chǎn)生者我們又稱之為消息源。消息源包括鼠標(biāo)器、鍵盤、串行端口中斷、有關(guān)的軟件工具、設(shè)備驅(qū)動(dòng)器、其它的輸入設(shè)備、其它的定位設(shè)備等等,甚至還可以是應(yīng)用程序自身。
由于事件是激發(fā)人機(jī)交互活動(dòng)最基本的因素,因而人機(jī)交互活動(dòng)的關(guān)鍵就是研究由事件產(chǎn)生的消息處理技術(shù)及其算法。用戶界面的質(zhì)量高低,在某種程度上取決于事件及消息管理技術(shù)的優(yōu)劣
3.1 事件驅(qū)動(dòng)機(jī)制的實(shí)現(xiàn)方法
以下列出本人所參與的注塑機(jī)械手控制軟件中,用于裝載鍵盤和鼠標(biāo)事件所產(chǎn)生消息的消息隊(duì)列的數(shù)據(jù)結(jié)構(gòu):
struct event_define
?。?
struct event_define *Last;
unsigned char ScanCode;
unsigned char KeyState;
int MouseState;
int CursorX;
int CursorY;
struct event_define *Next;
?。?
下面介紹這一結(jié)構(gòu)體中各個(gè)元素的功能:
● struct event define *Last 中的指針Last用于裝指向上一個(gè)消息隊(duì)列記錄的地址;
● struct event define *Next 中的指針Next用于裝指向下一個(gè)消息隊(duì)列記錄的地址。這兩個(gè)指針中的內(nèi)容是在消息隊(duì)列初始化過程中完成的,使消息隊(duì)列形成首尾相鏈的隊(duì)列,同時(shí)頭指針與尾指針都指向消息隊(duì)列中的默認(rèn)為0的消息數(shù)據(jù)記錄;
● unsigned char ScanCode中的ScanCode用于裝鍵盤敲擊事件發(fā)生時(shí),被敲擊鍵的鍵值;
● unsigned char KeyState中的KeyState用于裝鍵盤敲擊事件發(fā)生時(shí)當(dāng)時(shí)鍵的狀態(tài)(壓下或抬起);
● int MouseState中的MouseState用于裝鼠標(biāo)事件發(fā)生時(shí)鼠標(biāo)消息的內(nèi)容,如鼠標(biāo)左鍵壓下、左鍵抬起等;
● int CursorX和int CursorY中的CursorY和CursorX分別用于裝鼠標(biāo)事件發(fā)生時(shí)鼠標(biāo)在顯示屏上的坐標(biāo)值;本項(xiàng)目中有關(guān)消息的裝入都是用中斷方式來完成的,下面簡要介紹有關(guān)中斷處理的具體方法。
在程序中,當(dāng)鼠標(biāo)、鍵盤和串口數(shù)據(jù)事件發(fā)生時(shí),本程序把這類事件當(dāng)做中斷來處理。這樣做的好處在于:CPU不必花大量的時(shí)間去查尋外部事件是否產(chǎn)生。因?yàn)?,中斷事件何時(shí)發(fā)生是不能預(yù)知的,一旦有外部事件請求中斷,則會(huì)向CPU的接收中斷信號的引腳發(fā)出電信號,這些信號CPU是馬上可以知道的。如鍵盤何時(shí)有鍵按下,是隨機(jī)的,CPU不用反復(fù)查尋鍵盤狀態(tài),而可以去執(zhí)行其它程序,一旦有按鍵按下,鍵盤馬上產(chǎn)生中斷請求信號,CPU得知這信號后,便立即去執(zhí)行為鍵盤服務(wù)的中斷程序。服務(wù)完后,CPU又恢復(fù)執(zhí)行被中斷了的程序邏輯。
中斷方式處理事件的優(yōu)點(diǎn)在于:執(zhí)行速度快,可實(shí)時(shí)處理,不占用CPU過多的時(shí)間等優(yōu)點(diǎn)。注塑機(jī)械手控制軟件中,中斷服務(wù)程序完成的主要任務(wù)就是把中斷事件裝入相應(yīng)的消息隊(duì)列中。如:當(dāng)有鍵盤敲擊時(shí),就把鍵盤當(dāng)前被敲擊的鍵值及狀態(tài)放入消息隊(duì)列,緊接著把尾指針指向下一個(gè)消息隊(duì)列數(shù)據(jù)記錄。如果在鍵盤敲擊前,頭指針與尾指針指向同一個(gè)消息隊(duì)列數(shù)據(jù)記錄,則鍵盤敲擊后,尾指針指向了下一個(gè)消息隊(duì)列數(shù)據(jù)記錄,這樣頭指針與尾指針就指向了不同的消息隊(duì)列數(shù)據(jù)記錄。若此時(shí)又有新的消息進(jìn)入,則把它放入尾指針當(dāng)前消息隊(duì)列數(shù)據(jù)記錄中,并把尾指針前移,指向下一個(gè)消息隊(duì)列數(shù)據(jù)記錄。而主程序則用循環(huán)結(jié)構(gòu)不斷檢測消息隊(duì)列的頭指針與尾指針是否指向同一地址。若二者指向同一地址,則轉(zhuǎn)入下一次循環(huán),再次檢測消息隊(duì)列的頭指針與尾指針是否指向同一地址,如此反復(fù)。若某次檢測發(fā)現(xiàn)頭指針與尾指針指向了不同地址則說明有消息裝入消息隊(duì)列,此時(shí)主程序?qū)⒆x出消息內(nèi)容,并將頭指針向前移動(dòng),使之指向下一個(gè)消息隊(duì)列數(shù)據(jù)記錄的地址,接著對當(dāng)前消息做相應(yīng)的處理,處理完成后再次檢測消息隊(duì)列的頭指針與尾指針是否指向同一地址,若不同則做相應(yīng)處理,若相同則進(jìn)入下一輪循環(huán),如此反復(fù)。這樣由外部事件將消息放入消息隊(duì)列中,使尾指針前移;而主程序按先進(jìn)先出的順序讀出消息隊(duì)列中的數(shù)據(jù)記錄,并使頭指針向前移動(dòng),然后根據(jù)消息內(nèi)容做相應(yīng)處理。這種事件處理方式又稱消息處理機(jī)制,如圖1。
在上述消息處理的過程中易出現(xiàn)一種特殊情況,即消息密度較高,主程序處理的速度低于消息裝入消息隊(duì)列的速度,最后將導(dǎo)致消息隊(duì)列裝滿,卻仍有新消息產(chǎn)生。針對這種情況,有兩種處理方法,一種是忽略新來的消息;一種是用新來的消息覆蓋原來的消息。本程序采用的辦法是忽略新來的消息,直到消息隊(duì)列空出新的隊(duì)列數(shù)據(jù)記錄,才將空出隊(duì)列后產(chǎn)生的消息裝入隊(duì)列。如果這種情況發(fā)生,就會(huì)導(dǎo)致隊(duì)列裝滿后和在隊(duì)列空出新的數(shù)據(jù)記錄期間產(chǎn)生的消息不被響應(yīng)和處理,這種情況在程序?qū)嶋H運(yùn)行中是不允許發(fā)生的。為了避免這種主程序處理的速度低于消息進(jìn)入的速度的情況,可以采取的措施有三個(gè):
● 中斷服務(wù)程序用匯編語言編寫;
● 主程序消息處理部分盡量簡潔;
● 設(shè)定消息隊(duì)列的數(shù)據(jù)記錄個(gè)數(shù)足夠大。
[align=center]

圖1 消息處理機(jī)制[/align]
中斷服務(wù)程序用匯編語言編寫,這樣可以使得中斷服務(wù)程序更簡練,占用CPU時(shí)間更少,從而為主程序運(yùn)行提供了更長的時(shí)間。這樣就使得原來可能產(chǎn)生數(shù)據(jù)阻塞的情況,在用匯編語言編寫中斷程序后,主程序運(yùn)行分配的時(shí)間加長,主程序能夠完成消息處理,及時(shí)空出消息隊(duì)列數(shù)據(jù)記錄,為新來的消息提供數(shù)據(jù)記錄空間。
主程序消息處理部分盡量簡潔,就會(huì)加快主程序消息處理的速度,從而使主程序消息處理的速度大于消息裝入的速度。
設(shè)定消息隊(duì)列的數(shù)據(jù)記錄個(gè)數(shù)足夠大,這樣就會(huì)使新來的消息有一個(gè)足夠大的消息隊(duì)列數(shù)據(jù)記錄空間,就好比一個(gè)較大的緩沖區(qū),用以存放新來的消息數(shù)據(jù)。這樣即使新來的消息比較密集,也有一個(gè)比較大的空間存放。從而間接為主程序處理消息提供了時(shí)間。但實(shí)際上消息隊(duì)列數(shù)據(jù)記錄空間的大小是有上限的,所以在程序設(shè)計(jì)中這一問題的解決是由三個(gè)手段綜合解決的。