?? minigui 體系結(jié)構(gòu)之二 多窗口管理和控件及控件類.htm
字號:
<TBODY>
<TR>
<TD><PRE>清單 4 控件的子類化
#define IDC_CTRL1 100
#define IDC_CTRL2 110
#define IDC_CTRL3 120
#define IDC_CTRL4 130
#define MY_ES_DIGIT_ONLY 0x0001
#define MY_ES_ALPHA_ONLY 0x0002
static WNDPROC old_edit_proc;
static int RestrictedEditBox (HWND hwnd, int message, WPARAM wParam, LPARAM lParam)
{
if (message == MSG_CHAR) {
DWORD my_style = GetWindowAdditionalData (hwnd);
/* 確定被屏蔽的按鍵類型 */
if ((my_style & MY_ES_DIGIT_ONLY) && (wParam < '0' || wParam > '9'))
return 0;
else if (my_style & MY_ES_ALPHA_ONLY)
if (!((wParam >= 'A' && wParam <= 'Z') || (wParam >= 'a' && wParam <= 'z')))
/* 收到被屏蔽的按鍵消息,直接返回 */
return 0;
}
/* 由老的窗口過程處理其余消息 */
return (*old_edit_proc) (hwnd, message, wParam, lParam);
}
static int ControlTestWinProc (HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case MSG_CREATE:
{
HWND hWnd1, hWnd2, hWnd3;
CreateWindow (CTRL_STATIC, "Digit-only box:", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0,
10, 10, 180, 24, hWnd, 0);
hWnd1 = CreateWindow (CTRL_EDIT, "", WS_CHILD | WS_VISIBLE | WS_BORDER, IDC_CTRL1,
200, 10, 180, 24, hWnd, MY_ES_DIGIT_ONLY);
CreateWindow (CTRL_STATIC, "Alpha-only box:", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0,
10, 40, 180, 24, hWnd, 0);
hWnd2 = CreateWindow (CTRL_EDIT, "", WS_CHILD | WS_BORDER | WS_VISIBLE, IDC_CTRL2,
200, 40, 180, 24, hWnd, MY_ES_ALPHA_ONLY);
CreateWindow (CTRL_STATIC, "Normal edit box:", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0,
10, 70, 180, 24, hWnd, 0);
hWnd3 = CreateWindow (CTRL_EDIT, "", WS_CHILD | WS_BORDER | WS_VISIBLE, IDC_CTRL2,
200, 70, 180, 24, hWnd, MY_ES_ALPHA_ONLY);
CreateWindow ("button", "Close", WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, IDC_CTRL4,
100, 100, 60, 24, hWnd, 0);
/* 用自定義的窗口過程替換編輯框的窗口過程,并保存老的窗口過程。*/
old_edit_proc = SetWindowCallbackProc (hWnd1, RestrictedEditBox);
SetWindowCallbackProc (hWnd2, RestrictedEditBox);
break;
}
...
}
return DefaultMainWinProc (hWnd, message, wParam, lParam);
}
</PRE></TD></TR></TBODY></TABLE>
<P>在清單 4 中,程序首先定義了一個窗口處理過程,即 RestrictedEditBox 函數(shù)。然后,在利用 CreateWindow
函數(shù)建立控件時,將其中兩個編輯框的窗口處理過程通過 SetWindowCallbackProc 替換成了自己定義的
RestrictedEditBox 函數(shù),并且將該函數(shù)返回的值(即老的控件窗口處理過程地址)保存在了 old_edit_box
變量中。在建立這些編輯框之后,它們的消息將首先由 RestrictedEditBox 函數(shù)處理,然后在某些情況下才由老的窗口處理過程處理。</P>
<P>限于篇幅,另外兩種控件子類化的方法就不在這里講述。</P><STRONG>4.2 MiniGUI 中控件類的實現(xiàn)</STRONG>
<P>MiniGUI
函數(shù)庫實際維護了一個當前所有控件類的數(shù)據(jù)結(jié)構(gòu),其中包含了控件類名稱以及對應(yīng)的控件類信息。該數(shù)據(jù)結(jié)構(gòu)實際是一個哈希表,哈希表的每個入口包含由一個指針,該指針指向所有名程以某個字母開頭(不分大小寫)的控件類信息鏈表。控件類信息結(jié)構(gòu)定義如下:</P>
<TABLE class=code-sample cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><PRE>#define MAXLEN_CLASSNAME 15
typedef struct _CTRLCLASSINFO
{
char name [MAXLEN_CLASSNAME + 1];
// 控件類名程
/*
* common properties of this class
*/
DWORD dwStyle; // 控件類風格
HCURSOR hCursor; // 控件光標
int iBkColor; // 控件的背景顏色
int (*ControlProc)(HWND, int, WPARAM, LPARAM);
// 控件處理過程
DWORD dwAddData; // 附加數(shù)據(jù)
int nUseCount; // 使用計數(shù),即系統(tǒng)中屬于該控件類的控件個數(shù)
struct _CTRLCLASSINFO* next;
// 下一個控件類信息結(jié)構(gòu)
} CTRLCLASSINFO;
typedef CTRLCLASSINFO* PCTRLCLASSINFO;
</PRE></TD></TR></TBODY></TABLE>
<P>在控件類的數(shù)據(jù)結(jié)構(gòu)中包含了鼠標、光標、控件類的回調(diào)函數(shù)地址等等信息。在創(chuàng)建屬于該控件類的控件時,這些信息會復(fù)制到控件數(shù)據(jù)結(jié)構(gòu)中。這樣,新的控件實例就繼承了這種控件類的表象和行為。</P>
<P>該哈希表的哈希函數(shù)實際非常簡單,它的返回值就是控件類名稱首字母的英文字母表順序值:</P>
<TABLE class=code-sample cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><PRE>static int HashFunc (char* szClassname)
{
/* 判斷首字符是否為字母 */
if (!isalpha (szClassName[0])) return ERR_CTRLCLASS_INVNAME;
/* 講所有字符轉(zhuǎn)換為大寫 */
while (szClassName[i]) {
szClassName[i] = toupper(szClassName[i]);
i++;
if (i > MAXLEN_CLASSNAME)
return ERR_CTRLCLASS_INVLEN;
}
/* 獲得哈希值 */
return szClassName[0] - 'A';
}
</PRE></TD></TR></TBODY></TABLE>
<P>控件類的注冊和注銷函數(shù)非常簡單,這里不再贅述。</P><STRONG>4.3 MiniGUI 中控件的實現(xiàn)</STRONG>
<P>控件結(jié)構(gòu)相對復(fù)雜一些。其中包含了控件在父窗口中的位置信息、控件風格、擴展風格、控件鼠標、圖標、控件回調(diào)函數(shù)地址等等:</P>
<TABLE class=code-sample cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><PRE>typedef struct _CONTROL
{
/*
* 這些成員和 MAINWIN 結(jié)構(gòu)一致.
*/
short DataType; // 內(nèi)部使用的數(shù)據(jù)類型
short WinType; // 內(nèi)部使用的窗口類型
int left, top; // 控件在父窗口中的位置
int right, bottom;
int cl, ct; // 控件客戶區(qū)在父窗口中的位置
int cr, cb;
DWORD dwStyle; // 控件風格
DWORD dwExStyle; // 控件擴展風格
int iBkColor; // 背景顏色
HMENU hMenu; // 菜單句柄
HACCEL hAccel; // 加速鍵表句柄
HCURSOR hCursor; // 鼠標光標句柄
HICON hIcon; // 圖標句柄
HMENU hSysMenu; // 系統(tǒng)菜單句柄
HDC privCDC; // 私有 DC 句柄
INVRGN InvRgn; // 控件的無效區(qū)域
PGCRINFO pGCRInfo; // 控件的全局剪切區(qū)域
PZORDERNODE pZOrderNode;
// Z 序節(jié)點
// 僅對具有 WS_EX_CTRLASMAINWIN 擴展風格的控件有效
PCARETINFO pCaretInfo; // 插入符消息
DWORD dwAddData; // 控件附加數(shù)據(jù)
DWORD dwAddData2; // 控件附加數(shù)據(jù)
int (*ControlProc) (HWND, int, WPARAM, LPARAM); // 控件消息處理過程
char* spCaption; // 控件標題
int id; // 控件標識符,整數(shù)
SCROLLBARINFO vscroll; // 垂直滾動條信息
SCROLLBARINFO hscroll; // 水平滾動條信息
PMAINWIN pMainWin; // 包含該控件的主窗口
struct _CONTROL* pParent;// 控件的父窗口
/*
* Child windows.
*/
struct _CONTROL* children;
// 控件的第一個子控件
struct _CONTROL* active;
// 當前活動子控件
struct _CONTROL* old_under_pointer;
// 老的鼠標鼠標所在子控件
/*
* 下面這些成員只對控件有效
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -