基于linux和minigui的嵌入式系統軟件開發指南_第1頁
基于linux和minigui的嵌入式系統軟件開發指南_第2頁
基于linux和minigui的嵌入式系統軟件開發指南_第3頁
基于linux和minigui的嵌入式系統軟件開發指南_第4頁
基于linux和minigui的嵌入式系統軟件開發指南_第5頁
已閱讀5頁,還剩100頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、基于linux和minigui的嵌入式軟件開發指南基于 Linux 和 MiniGUI 的嵌入式系統軟件開發指南魏永明2001年目錄主題一:選擇MiniGUI-Threads 或者 MiniGUI-Lite3主題二:理解消息循環和窗口過程9主題三:對話框和控件編程20主題四:使用 GDI 函數34主題五:MiniGUI 1.1.0 版本引入的新 GDI 功能和函數52主題六:MiniGUI 提供的非 GUI/GDI 接口65主題七:MiniGUI 1.1.0 引入的新 GDI 功能和函數之二84主題八:MiniGUI和其他嵌入式Linux上的圖形及圖形用戶界面系統98主題一:選擇MiniGUI

2、-Threads 或者 MiniGUI-Lite自 MiniGUI 從 1998 年底推出以來,越來越多的人開始選擇 MiniGUI 在 Linux 上開發實時嵌入式系統。為了幫助嵌入式軟件開發人員使用 MiniGUI編寫出更好的應用程序,我們將撰寫一系列文章講解基于 Linux 和 MiniGUI 的嵌入式系統軟件開發,并冠名"基于 Linux 和 MiniGUI 的嵌入式系統軟件開發指南"。本文是該系列文章的第一篇,將講述如何針對具體項目選擇使用 MiniGUI-Threads 或者 MiniGUI-Lite 版本,并比較不同版本對系統軟件結構的影響。1:引言自 Min

3、iGUI 從 1998 年底推出以來,越來越多的人開始選擇 MiniGUI 在 Linux 上開發實時嵌入式系統。MiniGUI 系統也逐漸成熟,并在各種嵌入式系統中扮演了重要的角色。為了幫助嵌入式軟件開發人員使用 MiniGUI編寫出更好的應用程序,我們將撰寫一系列文章講解基于 Linux 和 MiniGUI 的嵌入式系統軟件開發,并冠名"基于 Linux 和 MiniGUI 的嵌入式系統軟件開發指南"。該系列文章將講述如何在基于 Linux 的系統上利用 MiniGUI 開發具有圖形用戶界面支持的嵌入式系統軟件,其內容不僅僅限于 MiniGUI 的編程,還會涉及到一些

4、Linux 下嵌入式系統軟件開發的技巧。系列文章的初步規劃如下:· 如何針對特定項目選擇 MiniGUI-Threads 和 MiniGUI-Lite · 理解消息循環和窗口過程 · 對話框和控件編程 · 使用 GDI 函數 · MiniGUI 和 Linux 系統調用 · MiniGUI-Lite 與進程間通訊 · 將 MiniGUI 及應用程序移植到特定平臺 · 利用 autoconf 接口編寫跨平臺代碼 · 如何調試 MiniGUI 應用程序 本文是該系列文章的第一篇,將講述如何針對具體項目選擇使用

5、 MiniGUI-Threads 或者 MiniGUI-Lite 版本,并比較不同版本對系統軟件結構的影響。2:MiniGUI-Threads 和 MiniGUI-Lite 的區別大家都知道,我們可以將 MiniGUI 編譯成兩個截然不同的版本,一個是 MiniGUI-Threads,一個是 MiniGUI-Lite。這兩個版本適用于不同的應用需求。在選擇到底使用 MiniGUI-Threads 還是 MiniGUI-Lite 之前,我們首先需要了解這兩個版本之間的區別。MiniGUI-Threads 是 MiniGUI 的最初版本。MiniGUI 最初為一個工業控制系統開發的,該系統功能單一

6、,但卻需要非常高的實時性,因此考慮將 MiniGUI 開發成一個基于多線程的圖形用戶界面支持系統。因為在傳統的 UNIX/Linux 系統上,典型的 GUI 系統(比如 X)采用傳統的基于 UNIX 套接字的客戶/服務器系統結構。在這種體系結構下,客戶建立窗口、繪制等等都要通過套接字傳遞到服務器,由服務器完成實質工作。這樣,系統非常依賴于 UNIX 套接字通訊。而大家都知道,UNIX 套接字的數據傳遞,要經過內核,然后再傳遞到另外一個程序。這樣,大量的數據在客戶/內核/服務器之間傳遞,從而增加了系統負荷,也占用了許多系統資源。這對許多嵌入式系統,尤其是實時性要求非常高的系統來說,是不可接受的。

7、為了解決這個問題,MiniGUI 首先采用了線程機制(類似Windows CE),所有的應用程序都運行在同一個地址空間,這樣,大大提高了程序之間的通訊效率,并且特別適合于實時性要求非常高的系統。這就是 MiniGUI-Threads。基于 MiniGUI-Threads 的程序,可以具有多個線程,每個線程有不同的功能和任務,并且可以建立各自的窗口,不同的線程之間,可以通過 MiniGUI 提供的消息傳遞機制進行事件傳送和同步。但顯然,這種基于線程的結構也導致了系統整體的脆弱如果某個線程因為非法的數據訪問而終止運行,則整個進程都將受到影響。不過,這種體系結構對實時控制系統等時間關鍵的系統來講,還

8、是非常適合的。為了解決 MiniGUI-Threads 版本因為線程而引入的一些問題,同時也為了讓 MiniGUI更加適合于嵌入式系統,我們決定開發一個 MiniGUI-Lite 版本。這個版本的開發目的是:· 保持與原先 MiniGUI 版本在源代碼級 99% 以上的兼容。 · 不再使用線程庫。 · 可以同時運行多個基于 MiniGUI-Lite 的應用程序,即多個進程,并且提供前后臺進程的切換。 顯然,要同時滿足上述三個目的,如果采用傳統的 C/S 結構對MiniGUI-Threads 進行改造,應該不難實現。但前面提到的傳統 C/S 結構的缺陷卻無法避免。經

9、過對 PDA 等嵌入式系統的分析,我們發現,某些 PDA 產品具有運行多個任務的能力,但同一時刻在屏幕上進行繪制的程序,一般不會超過兩個。因此,只要確保將這兩個進程的繪制相互隔離,就不需要采用復雜的 C/S 結構處理多個進程窗口之間的互相剪切。也就是說,在這種產品中,如果采用基于傳統 C/S 結構的多窗口系統,實際是一種浪費。有了上述認識,我們對 MiniGUI-Threads 進行了如下簡化設計:· 每個進程維護自己的主窗口 Z 序,同一進程創建的主窗口之間互相剪切。也就是說,除這個進程只有一個線程,只有一個消息循環之外,它與原有的 MiniGUI 版本之間沒有任何區別。每個進程在

10、進行屏幕繪制時,不需要考慮其他進程。 · 建立一個簡單的客戶/服務器體系,但確保最小化進程間的數據復制功能。因此,在服務器和客戶之間傳遞的數據僅限于輸入設備的輸入數據,以及客戶和服務器之間的某些請求和響應數據。 · 有一個服務器進程(mginit),它負責初始化一些輸入設備,并且通過 UNIX Domain 套接字將輸入設備的消息發送到前臺的 MiniGUI-Lite 客戶進程。 · 服務器和客戶被分別限定在屏幕的某兩個不相交矩形內進行繪制,同一時刻,只能有一個客戶及服務器進行屏幕繪制。其他客戶可繼續運行,但屏幕輸入被屏蔽。服務器可以利用 API 接口將某個客戶切

11、換到前臺。同時,服務器和客戶之間采用信號和 System V 信號量進行同步。 · 服務器還采用 System V IPC 機制提供一些資源的共享,包括位圖、圖標、鼠標、字體等等,以便減少實際內存的消耗。 從傳統 C/S 窗口系統的角度看,MiniGUI-Lite 的這種設計,無法處理達到完整的多窗口支持,這的確是一個結構設計上的不足和缺陷。不過,這實際是 MiniGUI-Lite 不同于其他窗口系統的一個特征。因為處理每個進程之間的互相剪切問題,將導致客戶和服務器之間的通訊量大大增加,但實際上在許多嵌入式系統當中這種處理是沒有必要的。在類似 PDA 的嵌入式系統中,往往各個程序啟動

12、后,就獨占屏幕進行繪制輸出,其他程序根本就沒有必要知道它現在的窗口被別的進程剪切了,因為它根本就沒有機會輸出到屏幕上。所以,在 MiniGUI-Lite 當中,當一個進程成為最頂層程序時,服務器會保證其輸出正常,而當有新的程序成為最頂層程序時,服務器也會保證其他程序不能輸出到屏幕上。但這些進程依然在正常執行著,不過,服務器只向最頂層的程序發送外部事件消息。表 1 給出了 MiniGUI-Threads 和 MiniGUI-Lite 的區別。從表中總結的區別看來,MiniGUI-Threads 適合于功能單一、實時性要求很高的系統,比如工業控制系統;而 MiniGUI-Lite 適合于功能豐富、

13、結構復雜、顯示屏幕較小的系統,比如 PDA 等信息產品。表 1 MiniGUI-Threads 和 MiniGUI-Lite 的區別MiniGUI-ThreadsMiniGUI-Lite多窗口支持完全不能處理進程間窗口的剪切,但提供進程內多窗口的完全支持字體支持支持點陣字體(VBF、RBF)和矢量字體(Adobe Type1 和 TrueType)目前尚不支持對 Adobe Type1 和 TrueType 等矢量字體的支持線程間消息傳遞通過 MiniGUI 的消息函數,可在不同的線程之間傳遞消息未考慮多線程應用,不能直接通過 MiniGUI 消息函數在不同線程之間傳遞消息多線程窗口MiniG

14、UI 能夠處理不同線程之間的窗口層疊不能處理多線程之間的窗口層疊其他基于線程的 C/S 結構,系統健壯性較差,因此要求系統經過嚴格測試采用 UNIX Domain Socket 的基于進程的 C/S 結構,可建立健壯的軟件架構。并提供了方便的高層 IPC 機制除上表中列出的不同之外,MiniGUI-Threads 和 MiniGUI-Lite 的 API 是一致的。3:MiniGUI-Threads 的典型應用和軟件架構本文介紹的基于 MiniGUI-Threads 典型應用是一個計算機數字控制(CNC)系統。這個系統是由清華大學基于 RT-Linux 建立的機床控制系統。該系統使用 Mini

15、GUI-Threads 作為圖形用戶界面支持系統。圖 1 是該 CNC 系統的用戶界面。圖 1 清華大學基于 RT-Linux 和 MiniGUI 的數控系統主界面圖 2 是該系統的架構。在用戶層,該系統有三個線程,一個作為 GUI 主線程存在,另一個作為監視線程監視系統的工作狀態,并在該線程建立的窗口上輸出狀態信息,第三個線程是工作線程,該線程執行加工指令,并通過 RT-Linux 的實時 FIFO 和系統的實時模塊進行通訊。圖 2 清華大學基于 RT-Linux 和 MiniGUI 的數控系統架構4:MiniGUI-Lite 的典型應用和軟件架構這里介紹的典型應用是一個基于 MiniGUI

16、-Lite 的 PDA。該 PDA 由國內某公司基于 Linux 開發,其上可以運行各種 PIM 程序、瀏覽器以及各種游戲程序。圖 3 是該 PDA 的用戶界面。圖 3 某公司開發的基于 MiniGUI 的 PDA 軟件界面該系統中的所有應用程序都以 Linux 進程的形式執行,mginit(即 MiniGUI-Lite)提供了輸入法支持和應用程序管理功能。當應用程序之間需要通訊時,可以通過 MiniGUI-Lite 所提供的 request/response 接口實現。圖 4 是該系統的架構。圖 4 某公司開發的基于 MiniGUI 的 PDA 軟件架構5:小結本文講解了 MiniGUI-T

17、hreads 和 MiniGUI-Lite 之間的區別,并舉例說明了基于這兩個不同版本的不同軟件架構。嵌入式程序開發人員必須明白這兩個版本之間的區別,并針對具體應用恰當選擇使用哪個版本。主題二:理解消息循環和窗口過程在利用 MiniGUI 開發應用程序之前,首先要理解的兩個概念就是消息循環和窗口過程。消息循環是事件驅動的 GUI 編程之基礎。而窗口則是圖形用戶界面的最基本交互元素。本文描述了 MiniGUI 中與消息相關的幾個重要函數,也描述了 MiniGUI-Threads 和 MiniGUI-Lite 在消息循環實現上的幾個不同。本文還講述了在 MiniGUI 中的窗口建立和銷毀過程,并解

18、釋了窗口過程的概念以及對一些重要消息的處理。1 引言我們知道,流行的 GUI 編程都有一個重要的概念與之相關,即"事件驅動編程"。事件驅動的含義就是,程序的流程不再是只有一個入口和若干個出口的串行執行線路;相反,程序會一直處于一個循環狀態,在這個循環當中,程序從外部輸入設備獲取某些事件,比如用戶的按鍵或者鼠標的移動,然后根據這些事件作出某種的響應,并完成一定的功能,這個循環直到程序接受到某個消息為止。"事件驅動"的底層設施,就是常說的"消息隊列"和"消息循環"。本文將具體描述 MiniGUI 中用來處理消息的幾個重

19、要函數,并描述 MiniGUI-Threads 和 MiniGUI-Lite 在消息循環實現上的一些不同。窗口是 MiniGUI 當中最基本的 GUI 元素,一旦窗口建立之后,窗口就會從消息隊列當中獲取屬于自己的消息,然后交由它的窗口過程進行處理。這些消息當中,有一些是基本的輸入設備事件,而有一些則是與窗口管理相關的邏輯消息。本文將講述 MiniGUI 中的窗口建立和銷毀過程,并解釋了窗口過程的概念以及對一些重要消息的處理。2 消息和消息循環在 MiniGUI 中,消息被如下定義(include/window.h):352 typedef struct _MSG 353 354 HWND hw

20、nd; 355 int message; 356 WPARAM wParam; 357 LPARAM lParam; 358 #ifdef _LITE_VERSION 359 unsigned int time; 360 #else 361 struct timeval time; 362 #endif 363 POINT pt; 364 #ifndef _LITE_VERSION 365 void* pAdd; 366 #endif 367 MSG; 368 typedef MSG* PMSG;一個消息由該消息所屬的窗口(hwnd)、消息編號(message)、消息的 WPARAM 型參數(

21、wParam)以及消息的 LPARAM 型參數(lParam)組成。消息的兩個參數中包含了重要的內容。比如,對鼠標消息而言,lParam 中一般包含鼠標的位置信息,而 wParam 參數中則包含發生該消息時,對應的 SHIFT 鍵的狀態信息等。對其他不同的消息類型來講,wParam 和 lParam 也具有明確的定義。當然,用戶也可以自定義消息,并定義消息的 wParam 和 lParam 意義。為了用戶能夠自定義消息,MiniGUI 定義了 MSG_USER 宏,可如下定義自己的消息:#define MSG_MYMESSAGE1 (MSG_USER + 1)#define MSG_MYMES

22、SAGE2 (MSG_USER + 2)用戶可以在自己的程序中使用自定義消息,并利用自定義消息傳遞數據。在理解消息之后,我們看消息循環。簡而言之,消息循環就是一個循環體,在這個循環體中,程序利用 GetMessage 函數不停地從消息隊列中獲得消息,然后利用 DispatchMessage 函數將消息發送到指定的窗口,也就是調用指定窗口的窗口過程,并傳遞消息及其參數。典型的消息循環如下所示:while (GetMessage (&Msg, hMainWnd) TranslateMessage (&Msg); DispatchMessage (&Msg);如上所示,Get

23、Message 函數從 hMainWnd 窗口所屬的消息隊列當中獲得消息,然后調用 TranslateMessage 函數將 MSG_KEYDOWN 和 MSG_KEYUP 消息翻譯成 MSG_CHAR 消息,最后調用 DispatchMessage 函數將消息發送到指定的窗口。在 MiniGUI-Threads 版本中,每個建立有窗口的 GUI 線程有自己的消息隊列,而且,所有屬于同一線程的窗口共享同一個消息隊列。因此,GetMessage 函數將獲得所有與 hMainWnd 窗口在同一線程中的窗口的消息。而在 MiniGUI-Lite 版本中,只有一個消息隊列,GetMessage 將從該

24、消息隊列當中獲得所有的消息,而忽略 hMainWnd 參數。3 幾個重要的消息處理函數除了上面提到的 GetMessage 和 TranslateMessage、DispatchMessage 函數以外,MiniGUI 支持如下幾個消息處理函數。PostMessage:該函數將消息放到指定窗口的消息隊列后立即返回。這種發送方式稱為"郵寄"消息。如果消息隊列中的郵寄消息緩沖區已滿,則該函數返回錯誤值。在下一個消息循環中,由 GetMessage 函數獲得這個消息之后,窗口才會處理該消息。PostMessage 一般用于發送一些非關鍵性的消息。比如在 MiniGUI 中,鼠標和

25、鍵盤消息就是通過 PostMessage 函數發送的。SendMessage:該函數和 PostMessage 函數不同,它在發送一條消息給指定窗口時,將等待該消息被處理之后才會返回。當需要知道某個消息的處理結果時,使用該函數發送消息,然后根據其返回值進行處理。在 MiniGUI-Threads 當中,如果發送消息的線程和接收消息的線程不是同一個線程,發送消息的線程將阻塞并等待另一個線程的處理結果,然后繼續運行;否則,SendMessage 函數將直接調用接收消息窗口的窗口過程函數。MiniGUI-Lite 則和上面的第二種情況一樣,直接調用接收消息窗口的窗口過程函數。SendNotifyMe

26、ssage:該函數和 PostMessage 消息類似,也是不等待消息被處理即返回。但和 PostMessage 消息不同,通過該函數發送的消息不會因為緩沖區滿而丟失,因為系統采用鏈表的形式處理這種消息。通過該函數發送的消息一般稱為"通知消息",一般用來從控件向其父窗口發送通知消息。PostQuitMessage:該消息在消息隊列中設置一個 QS_QUIT 標志。GetMessage 在從指定消息隊列中獲取消息時,會檢查該標志,如果有 QS_QUIT 標志,GetMessage 消息將返回 FALSE,從而可以利用該返回值終止消息循環。4 MiniGUI-Threads 和

27、 MiniGUI-Lite 在消息處理上的不同表 1 總結了 MiniGUI-Threads 和 MiniGUI-Lite 在消息處理上的不同表 1 MiniGUI-Threads 和 MiniGUI-Lite 在消息處理上的不同MiniGUI-ThreadsMiniGUI-Lite多消息隊列每個創建窗口的線程擁有獨立的消息隊列只有一個消息隊列。所有窗口共享一個消息隊列。除非嵌套消息循環,否則一個程序中只有一個消息循環。內建多線程處理是。可以自動處理跨線程的消息傳遞不能。從一個線程向另外一個線程發送或者郵寄消息時,必須通過互斥處理保護消息隊列。其他可以利用 PostSyncMessage 函數

28、跨線程發送消息,并等待消息的處理結果不能使用 PostSyncMessage、SendAsynMessage 等消息。5 窗口的建立和銷毀5.1 窗口的建立我們知道,MiniGUI 的 API 類似 Win32 的 API。因此,窗口的建立過程和 Windows 程序基本類似。不過也有一些差別。首先我們回顧一下 Windows 應用程序的框架:1. 在 WinMain () 中創建窗口,使用以下步驟:創建窗口類、登記窗口類、創建并顯示窗口、啟動消息循環。 2. 在 WndProc () 中,負責對發到窗口中的各種消息進行響應。 在 MiniGUI 中也同樣要有這兩個函數。不過稍微有點不同。程序

29、的入口函數名字叫MiniGUIMain (),它負責創建程序的主窗口。在建立主窗口之后,程序進入消息循環。在 Win32 程序中,在建立一個主窗口之前,程序首先要注冊一個窗口類,然后創建一個屬于該窗口類的主窗口。MiniGUI 卻沒有在主窗口中使用窗口類的概念。在 MiniGUI 程序中,首先初始化一個 MAINWINCREATE 結構,該結構中元素的含義是:CreateInfo.dwStyle:窗口風格CreateInfo.spCaption:窗口的標題CreateInfo.dwExStyle :窗口的附加風格CreateInfo.hMenu:附加在窗口上的菜單句柄CreateInfo.hC

30、ursor:在窗口中所使用的鼠標光標句柄CreateInfo.hIcon:程序的圖標CreateInfo.MainWindowProc:該窗口的消息處理函數指針CreateInfo.lx:窗口左上角相對屏幕的絕對橫坐標,以象素點表示CreateInfo.ty:窗口左上角相對屏幕的絕對縱坐標,以象素點表示CreateInfo.rx:窗口的長,以象素點表示CreateInfo.by:窗口的高,以象素點表示CreateInfo.iBkColor:窗口背景顏色CreateInfo.dwAddData:附帶給窗口的一個 32 位值CreateInfo.hHosting:窗口消息隊列所屬其中有如下幾點要特

31、別說明:1. CreateInfo.dwAddData:在程序編制過程中,應該盡量減少靜態變量,但是如何不使用靜態變量而給窗口傳遞參數呢?這時可以使用這個域。該域是一個 32 位的值,因此可以把所有需要傳遞給窗口的參數編制成一個結構,而將結構的指針賦予該域。在窗口過程中,可以使用 GetWindowAdditionalData 函數獲取該指針,從而獲得所需要傳遞的參數。 2. CreateInfo.hHosting:該域表示的是將要建立的主窗口使用哪個主窗口的消息隊列。使用其他主窗口消息隊列的主窗口,我們稱為"被托管"的主窗口。當然,這只在 MiniGUI-Threads

32、版本中有效。 3. MainWinProc 函數負責處理窗口消息。這個函數就是主窗口的"窗口過程"。窗口過程一般有四個入口參數,第一個是窗口句柄,第二個是消息類型,第三個和第四個是消息的兩個參數。 在準備好MAINWINCREATE 結構之后,就可以調用 CreateMainWindow 函數建立主窗口了。在建立主窗口之后,典型的程序將進入消息循環。如下所示:int MiniGUIMain (int args, const char* arg) MSG Msg; MAINWINCREATE CreateInfo; HWND hWnd; / 初始化 MAINWINCREATE

33、 結構 CreateInfo.dwStyle = WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | WS_CAPTION; CreateInfo.spCaption= "MiniGUI step three" CreateInfo.dwExStyle = WS_EX_NONE; CreateInfo.hMenu = createmenu(); CreateInfo.hCursor = GetSystemCursor(0); CreateInfo.hIcon = 0; CreateInfo.MainWindowProc = MainWinProc;

34、 CreateInfo.lx = 0; CreateInfo.ty = 0; CreateInfo.rx = 640; CreateInfo.by = 480; CreateInfo.iBkColor = COLOR_lightwhite; CreateInfo.dwAddData = 0; CreateInfo.hHosting = HWND_DESKTOP; / 建立主窗口 hWnd = CreateMainWindow(&CreateInfo); if (hWnd = HWND_INVALID) return 0; / 顯示主窗口 ShowWindow (hWnd, SW_SHO

35、WNORMAL); / 進入消息循環 while (GetMessage(&Msg, hWnd) TranslateMessage (&Msg); DispatchMessage(&Msg); MainWindowThreadCleanup (hWnd); return 0;注意,和 Windows 程序不同的是,在退出消息循環之后,還要調用一個函數,即 MainWindowThreadCleaup 函數。該函數的工作是銷毀主窗口的消息隊列,一般在線程或者進程的最后調用。5.2 窗口的銷毀要銷毀一個主窗口,可以利用 DestroyMainWindow (hWnd) 函數

36、。該函數將銷毀主窗口,但不會銷毀主窗口所使用的消息隊列,而要使用MainWindowThreadCleaup 最終清除主窗口所使用的消息隊列。一般而言,一個主窗口過程在接收到 MSG_CLOSE 消息之后會銷毀主窗口,并調用 PostQuitMessage 消息終止消息循環。如下所示:case MSG_CLOSE: / 銷毀窗口使用的資源 DestroyLogFont (logfont1); DestroyLogFont (logfont2); DestroyLogFont (logfont3); / 銷毀子窗口 DestroyWindow(hWndButton); DestroyWindow

37、(hWndEdit); / 銷毀主窗口 DestroyMainWindow (hWnd); / 發送 MSG_QUIT 消息 PostQuitMessage(hWnd); return 0;6 幾個重要消息在窗口(包括主窗口和子窗口在內)的生存周期當中,有幾個重要的消息需要仔細處理。下面描述這些消息的概念和典型處理。6.1 MSG_NCCREATE該消息在 MiniGUI 建立主窗口的過程中發送到窗口過程。lParam 中包含了由 CreateMainWindow 傳遞進入的 pCreateInfo 結構指針。您可以在該消息的處理過程中修改 pCreateInfo 結構中的某些值。6.2 MS

38、G_SIZECHANGING該消息窗口尺寸發生變化時,或者建立窗口時發送到窗口過程,用來確定窗口大小。wParam 包含預期的窗口尺寸值,而 lParam 用來保存結果值。MiniGUI 的默認處理是,case MSG_SIZECHANGING: memcpy (PRECT)lParam, (PRECT)wParam, sizeof (RECT); return 0;你可以截獲該消息的處理,從而讓即將創建的窗口位于指定的位置,或者具有固定的大小,比如在 SPINBOX 控件中,就處理了該消息,使之具有固定的大?。篶ase MSG_SIZECHANGING: const RECT* rcExpe

39、ct = (const RECT*) wParam; RECT* rcResult = (RECT*) lPraram; rcResult->left = rcExpect->left; rcResult->top = rcExpect->top; rcResult->right = rcExpect->left + _WIDTH; rcResult->bottom = rcExpect->left + _HEIGHT; return 0;6.3 MSG_CHANGESIZE在確立窗口大小之后,該消息被發送到窗口過程,用來通知確定之后的窗口大小。

40、wParam 包含了窗口大小 RECT 的指針。注意應用程序應該將該消息傳遞給 MiniGUI 進行默認處理。6.4 MSG_SIZECHANGED該消息用來確定窗口客戶區的大小,和 MSG_SIZECHANGING 消息類似。wParam 參數包含窗口大小信息,lParam 參數是用來保存窗口客戶區大小的 RECT 指針,并且具有默認值。如果該消息的處理返回非零值,則將采用 lParam 當中包含的大小值作為客戶區的大小;否則,將忽略該消息的處理。比如在 SPINBOX 控件中,就處理了該消息,并使客戶區占具所有的窗口范圍:case MSG_SIZECHANGED RECT* rcClien

41、t = (RECT*) lPraram; rcClient->right = rcClient->left + _WIDTH; rcClient->bottom = rcClient->top + _HEIGHT; return 0;6.5 MSG_CREATE該消息在建立好的窗口成功添加到 MiniGUI 的窗口管理器之后發送到窗口過程。這時,應用程序可以在其中創建子窗口。如果該消息返回非零值,則將銷毀新建的窗口。注意,在 MSG_NCCREATE 消息被發送時,窗口尚未正常建立,所以不能在 MSG_NCCREATE 消息中建立子窗口。6.6 MSG_PAINT該消息

42、在需要進行窗口重繪時發送到窗口過程。MiniGUI 通過判斷窗口是否含有無效區域來確定是否需要重繪。當窗口在初始顯示、從隱藏狀態變化為顯示狀態、從部分不可見到可見狀態,或者應用程序調用 InvalidateRect 函數使某個矩形區域變成無效時,窗口將具有特定的無效區域。這時,MiniGUI 將在處理完所有的郵寄消息、通知消息之后處理無效區域,并向窗口過程發送 MSG_PAINT 消息。該消息的典型處理如下:case MSG_PAINT: HDC hdc; hdc = BeginPaint (hWnd); / 使用 hdc 繪制窗口 . EndPaint (hWnd, hdc); break;

43、6.7 MSG_DESTROY該消息在應用程序調用 DestroyMainWindow 或者 DestroyWindow 時發送到窗口過程當中,用來通知系統即將銷毀一個窗口。如果該消息的處理返回非零值,則將取消銷毀過程。7 Hello, World在這個小節當中,我們給出一個簡單的示例程序,該程序在窗口中打印"Hello, world!":#include <stdio.h>#include <stdlib.h>#include <string.h>#include <minigui/common.h>#include <

44、;minigui/minigui.h>#include <minigui/gdi.h>#include <minigui/window.h>static int HelloWinProc (HWND hWnd, int message, WPARAM wParam, LPARAM lParam) HDC hdc; switch (message) case MSG_PAINT: hdc = BeginPaint (hWnd); TexOut (hdc, 0, 0, "Hello, world!"); EndPaint (hWnd, hdc);

45、break; case MSG_CLOSE: DestroyMainWindow (hWnd); PostQuitMessage (hWnd); return 0; return DefaultMainWinProc(hWnd, message, wParam, lParam);static void InitCreateInfo (PMAINWINCREATE pCreateInfo) pCreateInfo->dwStyle = WS_CAPTION | WS_VISIBLE; pCreateInfo->dwExStyle = 0; pCreateInfo->spCapt

46、ion = "Hello, world!" ; pCreateInfo->hMenu = 0; pCreateInfo->hCursor = GetSystemCursor (0); pCreateInfo->hIcon = 0; pCreateInfo->MainWindowProc = HelloWinProc; pCreateInfo->lx = 0; pCreateInfo->ty = 0; pCreateInfo->rx = 320; pCreateInfo->by = 240; pCreateInfo->iB

47、kColor = PIXEL_lightwhite; pCreateInfo->dwAddData = 0; pCreateInfo->hHosting = HWND_DESKTOP;int MiniGUIMain (int args, const char* arg) MSG Msg; MAINWINCREATE CreateInfo; HWND hMainWnd;#ifdef _LITE_VERSION SetDesktopRect (0, 0, 800, 600);#endif InitCreateInfo (&CreateInfo); hMainWnd = Crea

48、teMainWindow (&CreateInfo); if (hMainWnd = HWND_INVALID) return -1; while (GetMessage (&Msg, hMainWnd) DispatchMessage (&Msg); MainWindowThreadCleanup (hMainWnd); return 0;很顯然,這是一個非常簡單的程序。該程序使用了 MiniGUI 的默認過程來處理我們前面提到的許多消息,而僅僅處理了 MSG_PAINT 和 MSG_CLOSE 兩條消息。當用戶單擊標題欄上的關閉按鈕時,MiniGUI 將發送 MSG

49、_CLOSE 到窗口過程。這時,應用程序就可以銷毀窗口,并終止消息循環,最終退出程序。 8 小結本文描述了 MiniGUI 中與消息相關的幾個重要函數,并講述了 MiniGUI-Threads 和 MiniGUI-Lite 在消息機制實現上的幾個不同。本文還講述了在 MiniGUI 中的窗口建立和銷毀過程,并解釋了窗口過程的概念以及一些重要消息的處理。最后,本文給出了一個簡單的 MiniGUI 的示例程序,該程序建立窗口,并在其中打印"Hello, world!"。主題三:對話框和控件編程本文講述 MiniGUI 中的對話框和控件編程。首先講解 MiniGUI 中的控件類和

50、控件實例的關系,并舉例說明控件子類化的概念及應用;其次講解 MiniGUI 對話框的編程技術,包括對話框模板的定義和對話框回調函數的編程;最后解釋模態對話框和非模態對話框之間的區別。1 引言對話框編程是一個快速構建用戶界面的技術。通常,我們編寫簡單的圖形用戶界面時,可以通過調用 CreateWindow 函數直接創建所有需要的子窗口,即控件。但在圖形用戶界面比較復雜的情況下,每建立一個控件就調用一次 CreateWindow 函數,并傳遞許多復雜參數的方法很不可取。主要原因之一,就是程序代碼和用來建立控件的數據混在一起,不利于維護。為此,一般的 GUI 系統都會提供一種機制,利用這種機制,通過

51、指定一個模板,GUI 系統就可以根據此模板建立相應的主窗口和控件。MiniGUI 也提供這種方法,通過建立對話框模板,就可以建立模態或者非模態的對話框。本文首先講解組成對話框的基礎,即控件的基本概念,然后講解對話模板的定義,并說明模態和非模態對話框之間的區別以及編程技術。2 控件和控件類許多人對控件(或者部件,widget)的概念已經相當熟悉了。控件可以理解為主窗口中的子窗口。這些子窗口的行為和主窗口一樣,即能夠接收鍵盤和鼠標等外部輸入,也可以在自己的區域內進行輸出只是它們的所有活動被限制在主窗口中。MiniGUI 也支持子窗口,并且可以在子窗口中嵌套建立子窗口。我們將 MiniGUI 中的所

52、有子窗口均稱為控件。在 Windows 或 X Window 中,系統會預先定義一些控件類,當利用某個控件類創建控件之后,所有屬于這個控件類的控件均會具有相同的行為和顯示。利用這些技術,可以確保一致的人機操作界面,而對程序員來講,可以像搭積木一樣地組建圖形用戶界面。MiniGUI 使用了控件類和控件的概念,并且可以方便地對已有控件進行重載,使得其有一些特殊效果。比如,需要建立一個只允許輸入數字的編輯框時,就可以通過重載已有編輯框而實現,而不需要重新編寫一個新的控件類。如果讀者曾經編寫過 Windows 應用程序的話,應該記得在建立一個窗口之前,必須確保系統中存在新窗口所對應的窗口類。在 Win

53、dows 中,程序所建立的每個窗口,都對應著某種窗口類。這一概念和面向對象編程中的類、對象的關系類似。借用面向對象的術語,Windows 中的每個窗口實際都是某個窗口類的一個實例。在 X Window 編程中,也有類似的概念,比如我們建立的每一個 Widget,實際都是某個 Widget 類的實例。這樣,如果程序需要建立一個窗口,就首先要確保選擇正確的窗口類,因為每個窗口類決定了對應窗口實例的表象和行為。這里的表象指窗口的外觀,比如窗口邊框寬度,是否有標題欄等等,行為指窗口對用戶輸入的響應。每一個 GUI 系統都會預定義一些窗口類,常見的有按鈕、列表框、滾動條、編輯框等等。如果程序要建立的窗口

54、很特殊,就需要首先注冊一個窗口類,然后建立這個窗口類一個實例。這樣就大大提高了代碼的可重用性。在 MiniGUI 中,我們認為主窗口通常是一種比較特殊的窗口。因為主窗口代碼的可重用性一般很低,如果按照通常的方式為每個主窗口注冊一個窗口類的話,則會導致額外不必要的存儲空間,所以我們并沒有在主窗口提供窗口類支持。但主窗口中的所有子窗口,即控件,均支持窗口類(控件類)的概念。MiniGUI 提供了常用的預定義控件類,包括按鈕(包括單選鈕、復選鈕)、靜態框、列表框、進度條、滑塊、編輯框等等。程序也可以定制自己的控件類,注冊后再創建對應的實例。表 1 給出了 MiniGUI 預先定義的控件類和相應類名稱

55、定義。表 1 MiniGUI 預定義的控件類和對應類名稱控件類類名稱宏定義備注靜態框"static"CTRL_STATIC按鈕"button"CTRL_BUTTON列表框"listbox"CTRL_LISTBOX進度條"progressbar"CTRL_PRORESSBAR滑塊"trackbar"CTRL_TRACKBAR單行編輯框"edit"、"sledit"CTRL_EDIT、CTRL_SLEDIT多行編輯框"medit"、"mledit"CTRL_MEDIT、CTRL_MLEDIT工具條"toolbar"CTRL_TOOLBAR菜單按鈕"menubutton"CTRL_ME

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論