[轉貼]GP1288編程快速入門

所有GP1288 的技術文章將放在這裡
本板部分文章來自樂酷網,轉貼繁體版屬娛樂酷網站長授權,未經允許,嚴禁轉貼至其他網站

版主: 總版面管理員

回覆文章
Mowd
系統管理員
系統管理員
文章: 1828
註冊時間: 2003-07-16 6:31 PM
來自: 台灣台北
聯繫:

[轉貼]GP1288編程快速入門

文章 Mowd »

GP1288編程快速入門
www.wqxnet.com 2002-7-28 Wqx.NET

使用SDK編寫GP1288程式十分類似使用Windows 3.1 的SDK,我們使用Win32 like 的API。作為快速入門,這篇文章只涉及到最基本的調用,目標人群是以前沒接觸過Windows編程的人員,我們希望通過它帶您走進GP1288的神奇世界。不過要想成為高手,您還應該閱讀“API列表“和”程式師指南“。
1.程式入口點
在程式檔中,一定要有一個並且只能有一個主函數,就是WinMain()。大家不用懷疑,我們並不需要像在C程式中那樣定義main()函數,實際上在編譯連接時,WinMain()函數已經連接了一個系統定義過的main()主程序。
WinMain()函數的結構原型是:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int nCmdShow)
當我們新建立一個工程時,這個入口已經定義在系統預建的檔StdPDA.c中了。我們要做的就是從這個檔開始,在主程序中添加內容。
2.使用視窗
.註冊視窗類
 視窗總是在視窗類的基礎上創建的,視窗類定義了視窗過程和基於此類創建的視窗的其他一些特性。在為程式創建視窗之前,必需首先調用RegisterClass註冊一個視窗類。
 WNDCLASS是系統預定好的一個結構類型,通常我們像這樣: 
WNDCLASSwndclass;
  接下來我們初始化該結構的10個域。這些域的說明如下:
style類風格的標誌符,我們可以使用C的按位元“或”操作組合出不同的風格。
在頭文件\include\pc\wm\winuser.h中定義了一個以CS為首碼的標誌符集合:
#define CS_VREDRAW 0x0001
#define CS_HREDRAW 0x0002
#define CS_DBLCLKS 0x0008
#define CS_OWNDC 0x0020
#define CS_CLASSDC 0x0040
#define CS_PARENTDC 0x0080
#define CS_NOCLOSE 0x0200
#define CS_SAVEBITS 0x0800
#define CS_BYTEALIGNCLIENT 0x1000
#define CS_BYTEALIGNWINDOW 0x2000
#define CS_GLOBALCLASS 0x4000
一般來說,如果我們希望有筆觸動作,視窗橫向尺寸(CS_HERDRAW)和縱向尺寸(CS_VERDRAW)變化時刷我們應該設定
wndclass.flag= CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
lpfnWndProc 定義視窗類過程,這個過程將處理基於這個視窗類創建的所有視窗的全部消息。這些消息 包括按鍵接收,筆觸,等等,而這個視窗過程是我們後面一定要寫的。
cbClsExtra
cbWndExtra 這兩個域用於在類結構和MicroWindow內部保存的視窗結構中預留一些額外空間,一般我們將其設為0
hInstance  這個是程式的實例控制碼,我們一般也設為0
hIcon  為所有基於這個視窗類建立的視窗設置一個圖示
hCursor  游標設置。上述兩項我們一般也設為0
hInstance  指定基於這個類創建的視窗背景顏色。GetStockObject()函數調用將返回系統定義的一個標準背景顏色刷控制碼,比如如下設置
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
意味著視窗客戶區域的背景完全為白色。
lpszMenuName 視窗類功能表名。通過這個名稱,系統才能得到我們寫在 .rc檔中的功能表細節。
lpszClassName 我們所定義的這個類名。
 當我們初始化了這個結構的這10個域後,我們就要調用RegisterClass來註冊這個視窗類。該函數只有一個參
 數,即指向WNDCLASS結構的指標。例如:
RegisterClass (&wndclass);
.創建窗口
 這裏有兩個函數可供調用,以來創建窗口:CreateWindow()和CreateWindowEx()。實際上它們的效果是完全相同的,我們推薦使用簡單點的函數CreateWindow()。它的函數原型如下:
HWND WINAPI CreateWindow(LPCSTR lpClassName, LPCSTR lpWindowName,
DWORD dwStyle, int x, int y, int nWidth, int nHeight,
HWND hwndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
 這一大堆參數的意義如下:
lpclassName這個參數必需填寫,其值即是我們上面註冊視窗是用的類名。
lpWindowNamewindow的標題名。
dwStylewindow的風格選項。系統預定了許多常量,例如:
WS_OVERLAPPEDWINDOW多層窗口
WS_VISIBLE可視的
WS_CHILD子視窗,沒有功能表功能
其他常量定義請見 include\pc\mwin\winuser.h
x ,y 視窗左上角座標位置(以圖元為單位,GP1288為160x240圖元)
nWidth,nHeight 表單大小
hwndParent上層窗口指標。注意如設置了WS_CHILD,此項一定不可為空
hMenu視窗功能表名稱。如果我們在上面的註冊中已經指定了此名稱,這裏可以寫NULL
其他未特殊指定的參數我們一般都要填 0調用創建函數之後,會返回被創建視窗的控制碼,類型為HWND型(窗口控制碼類型)。在這裏每個視窗都有一個控制碼,程式用控制碼來引用視窗。
 所以一定記住要將此返回控制碼值保存起來,例如:
HWNDhwnd;
hwnd = CreateWindowEx(...);
.顯示視窗
  這時我們在內部已經創建了一個視窗,系統已經分配了記憶體保存此視窗的全部資訊,但視窗並未在顯示幕上顯示出來。這時我們使用:
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
ShowWindow()在顯示幕上顯示視窗,hwnd即是我們剛才創建視窗的控制碼。
UpdateWindow()調用通過發送WM_PAINT消息使得表單被繪製。

3.消息迴圈
現在我們應該讀入用戶鍵盤和滑鼠輸入的資料。系統為每個當前運行的Window程式維護一個“消息佇列”,在發生事件之後,這些事件被轉換為“消息”,並放入程式消息佇列中。
我們一般使用如下這樣一段“消息迴圈”代碼來從消息佇列中取出消息:
MSGmsg;
while (GetMessage(&msg,NULL,0,0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
類型MSG在winuser.h中定義。通過GetMessage()函數的調用,從消息佇列中取出一個消息,傳遞給系統一個指向名為msg的MSG結構指標。GetMessage的第二、三、四個參數設置為NULL或0,表示程式接受他自己創建的所有視窗的所有消息。
TranslateMessage(&msg)將msg結構傳給系統進行鍵盤轉換。
DispatchMessage(&msg)又將msg結構傳給系統,然後系統將該消息發送給適當的視窗過程,讓它來進行處理。
4.視窗過程和消息處理
實際上以上我們作的只是準備性質的工作,實質上的動作發生在視窗過程中。視窗過程確定了在視窗的客戶區域中顯示什麼內容,以及視窗怎樣相應用戶輸入。
一個程式可以包含多個視窗過程,視窗過程總是與調用RegisterClass註冊的特定視窗類相關聯。窗口過程一般定義為如下形式:
LRESULT WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
在這裏WinProc的參數實際上是上面所講的消息迴圈中msg結構中的內容。
視窗過程接受的消息都是用一個數值來標記的,即message參數。在winuser.h中定義了以“WM”為首碼的常量來區分每個消息。一般來說我們使用switch和case結構來判斷接收的是什麼消息和如何適當的處理他們。例如:
switch(message){
case WM_CREATE:
[處理視窗創建消息]
return 0;
case WM_PAINT:
[處理視窗繪製消息]
return 0;
case WM_DESTORY:
[處理視窗銷毀消息]
return 0;
......
default:
return DefWindowProc(hWnd,message,wParam,lParam);
}
大家可能要問,這些消息是從哪里來的呢?實際上,當我們開始調用CreateWindow()時,WM_CREATE就被發送出去了;當我們調用 UpdateWindow()時,就產生了WM_PAINT消息。
在這當中WM_PAINT消息是很重要的。當視窗客戶區域的一部分或者全部變為“無效”,以至於必須“刷新”是,將由這個消息通知程式。
對WM_PAINT的處理幾乎總是從一個BeginPaint調用開始的:
hdc = BeginPaint (hWnd, &ps);並用一個EndPaint調用結束:
EndPaint (hWnd, &ps);
參數&ps是指向類型為PAINT_STRUCT的結構指標。
而DefWindowProc()函數來為視窗過程不予處理的所有消息提供默認處理。
5.GDI簡介
圖形設備介面(GDI:Grahpics Device Interface)是非常重要的部分,它負責在螢幕上顯示圖形。GDI由百餘個函數組成。
.獲取設備描述表控制碼
GDI函數必須通過設備描述表(簡稱DC)控制碼來控制繪圖。DC實際上是GDI內部保存的資料結構。所以當我們需要繪圖時必須先獲得設備描述表控制碼,而繪圖完畢後必須釋放設備描述表控制碼。程式必須在處理單個消息期間獲得和釋放控制碼。
我們可以使用GetDC()函數來獲取控制碼,它的函數原型為:
HDC WINAPI GetDC(HWND hwnd);
在使用完成後,要調用ReleaseDC()函數來釋放控制碼。注意的是,這兩個函數一定要成對使用。例如:
hdc = GetDC(hwnd);
oldfont = SelectObject(hdc,CreateFont(12,0,0,0,0,0,0,0,0,0,0,0, FF_DONTCARE | DEFAULT_PITCH, "HZXFONT"));
sprintf(output, "%25s", "hello");
TextOut(hdc, 2, 2, output, 25);
ReleaseDC(hwnd,hdc);
另一種獲得控制碼的方法是在處理WM_PAINT消息時,因為我們總是成對調用BeginPaint()和EndPaint(),而BeginPaint返回的值就是設備描述表控制碼。一般我們這樣處理WM_PAINT消息:
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
[這時我們就可以使用GDI函數了〕
EndPaint(hwnd,&ps);
return 0;
.GDI函數
想輸出文本,我們可以使用:
BOOL WINAPI TextOut(HDC hdc, int x, int y, LPCSTR lpszString, int iLength);
它讓我們在指定位置(x,y)輸出lpszString指向的長度為iLength的字串
需要注意的是,當我們需要輸出文本時,要使用SelectObject()函數指定字體,否則將用6*13的ASCII字體默認顯示。
想繪製圖像,我們可以使用許多函數,比如:
COLORREF WINAPI SetPixel(HDC hdc, int x, int y, COLORREF crColor);
它在指定的x和y座標以特定的顏色設置圖元
BOOL WINAPI MoveToEx(HDC hdc, int x, int y, LPPOINT lpPoint);
BOOL WINAPI LineTo(HDC hdc, int x, int y);
這兩個函數用來畫線,第一個函數指定了線的開始點,第二個函數則指定了線的終點。
BOOL WINAPI Rectangle(HDC hdc, int nLeft, int nTop, int nRight, int nBottom);
這個函數用來畫矩形。點(nLeft,nTop)是矩形的左上角,點(nRight,nBottom)是矩形的右下角。
BOOL WINAPI Polygon(HDC hdc, CONST POINT *lpPoints, int nCount);
這是畫帶邊界框的填充圖形的函數,lpPoints是POINT結構的一個陣列,nCount是點的個數。
BOOL WINAPI DrawDIB(HDC hdc,int x,int y,PMWIMAGEHDR pimage);
我們用它來在指定的(x,y)位置繪製pimage指定的一幅圖像。
.輸入法使用
當我們的應用程式使用到輸入法時,以下函數可供調用:
HWND InitXime (HWND owner, InputMethod ime);
初使化輸入法。InputMethod是系統定義的枚舉類型的結構,我們可以選定輸入法介面出現的形態:
XIME_NONE// 最小化方式,此時輸入法在螢幕上縮小為一個小型圖示
XIME_ASCII,// 字母與數位
XIME_SYMBOL,// 符號
XIME_PHONE,// 電話符號
XIME_CJ,// 繁體倉頡輸入法
XIME_BOSHIAMY,// 繁體無蝦米輸入法
XIME_HANDWRITE,// 手寫輸入
XIME_SPCODE,// 大寫符號
XIME_PINYIN,// 全拼
XIME_WUBI,// 五筆
XIME_DEFAULT,// 上次預設值
void SelectXime(InputMethod ime);
在使用中切換輸入法
void DestroyXime (void);
手工銷毀輸入法
6.鍵盤與觸控
鍵盤與手寫屏的觸控是兩個標準的用戶輸入源,它們以消息的形式傳遞給程式的視窗過程。雖然鍵盤是用戶輸入的主要來源,但是程式不必對它接收的所有消息都做出回應,比如背光的動作,當我們按下開關鍵兩秒後背光打開,這就是系統本身處理的鍵盤功能。通常默認的處理方式是由DefWindowProc處理的。對話方塊也有鍵盤介面,但是當對話方塊處於活動狀態時,應用程式通常不必監視鍵盤,系統處理所有編輯控制邏輯,並在輸入完畢後將編輯控制的最終內容傳送給程式。通過使用處理鍵盤和觸控輸入的子視窗控制,來將較高層的資訊傳遞回父視窗,我們就不會因為處理鍵盤消息而煩惱。
當我們按下鍵時,系統會將此消息放入消息佇列,我們就可以採用上述的消息處理機制來分支處理。比如:
WM_KEYDOWN功能鍵按下
WM_KEYUP功能鍵釋放
WM_LBUTTONDOWN筆觸按下
WM_LBUTTONUP筆觸釋放
我們處理按鍵消息時,比如WM_KEYDOWN,在它的wParam參數中傳遞有虛擬鍵碼,此代碼標誌按下的鍵。大多數虛擬鍵碼的名稱在winuser.h中定義,都以VK_開頭。例如:
VK_PRIOR滾輪向上
VK_SELECT滾輪壓下
VK_NEXT滾輪向下
VK_ESCAPE跳出鍵
VK_UP方向鍵上
VK_DOWN方向鍵下
VK_LEFT方向鍵左
VK_RIGHT方向鍵右
VK_HOME功能鍵一
VK_END功能鍵二
一般我們用如下的代碼來分支處理按鍵消息:
case WM_KEYDOWN:
chCharCode = (TCHAR) wParam;
switch (chCharCode) {
case VK_LEFT:
[處理方向鍵左]
break;
case VK_RIGHT:
[處理方向鍵右]
break;
case VK_UP:
[處理方向鍵上]
break;
case VK_DOWN:
[處理方向鍵下]
break;
...
default:
return 0;
}

7.控制項
我們提供了標準的控制項,比如:按鈕、核取方塊、編輯框、列表框、下拉式列示方塊、文本框和捲軸。當我們使用功能表或在對話方塊中使用控制項時,我們需要通過編寫資源描述檔(.rc)來定義這些控制項。
實際上在我們進行編譯時,尾碼.rc的資源檔案通過工具被轉換為C檔,然後編譯連接其他檔一起形成可執行檔。我們看一個資源檔案的例子:
BRMENU MENU DISCARDABLE
BEGIN
POPUP "Game"
BEGIN
MENUITEM "Instructions",IDM_DLGBOX
MENUITEM "New Game",ID_NEW
MENUITEM SEPARATOR
MENUITEM "Exit",ID_CLOSE
END
POPUP "HELP"
BEGIN
MENUITEM "About Gnibbles",ID_ABOUT
END
END
關於控制項的詳細使用,您還要閱讀其他書籍,或是我們提供的實例程式。

結語
我們不希望您只通過這篇小文就能夠編寫出美倫美煥的應用程式,正入開篇所說的,這只是冰山的一角。不過大家也可以發現,使用SDK進行GP1288的開發是件輕鬆而充滿創造力的事情。讓我們向高手之路邁進吧。
原作者: GGV
來源: GGV
Mowd 與你的交流天地
歡迎您的到來
回覆文章