📄 基于 linux 和 minigui 的嵌入式系统软件开发指南(三).htm
字号:
"This is child static control",
WS_CHILD | SS_NOTIFY | SS_SIMPLE | WS_VISIBLE | WS_BORDER,
IDC_STATIC1,
20, 110, 100, 50, hStaticWnd1, 0);
hEdit2 = CreateWindow (CTRL_EDIT,
"Edit Box 2",
WS_CHILD | WS_VISIBLE | WS_BORDER,
IDC_EDIT2,
0, 20, 100, 24, hStaticWnd2, 0);
break;
}
.......
}
return DefaultMainWinProc (hWnd, message, wParam, lParam);
}
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P>用户也可以通过 RegisterWindowClass
函数注册自己的控件类,并建立该控件类的控件实例。如果程序不再使用某个自定义的控件类,则应该使用 UnregisterWindowClass
函数注销自定义的控件类。上述两个函数以及和窗口类相关函数的原型如下(include/window.h):</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>897 BOOL GUIAPI RegisterWindowClass (PWNDCLASS pWndClass);
898 BOOL GUIAPI UnregisterWindowClass (const char* szClassName);
899 char* GUIAPI GetClassName (HWND hWnd);
900 BOOL GUIAPI GetWindowClassInfo (PWNDCLASS pWndClass);
901 BOOL GUIAPI SetWindowClassInfo (const WNDCLASS* pWndClass);
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P>RegisterWindowClass 通过 pWndClass 结构注册一个控件类;UnregisterWindowClass
函数则注销指定的控件类;GetClassName
活得窗口的对应窗口类名称,对主窗口而言,窗口类名称为"MAINWINDOW";GetWindowClassInfo
分别用来获取和指定特定窗口类的属性。</P>
<P>清单 2 中的程序,定义并注册了一个自己的控件类。该控件用来显示安装程序的步骤信息,MSG_SET_STEP_INFO
消息用来定义该控件中显示的所有步骤信息,包括所有步骤名称及其简单描述。MSG_SET_CURR_STEP
消息用来指定当前步骤,控件将高亮显示当前步骤。</P>
<P>清单2 定义并注册自定义控件类</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>#define STEP_CTRL_NAME "mystep"
#define MSG_SET_STEP_INFO (MSG_USER + 1)
#define MSG_SET_CURR_STEP (MSG_USER + 2)
static int StepControlProc (HWND hwnd,
int message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
HELPWININFO* info;
switch (message) {
case MSG_PAINT:
hdc = BeginPaint (hwnd);
/* 获取步骤控件信息 */
info = (HELPWININFO*)GetWindowAdditionalData (hwnd);
/* 绘制步骤内容 */
......
EndPaint (hwnd, hdc);
break;
/* 控件自定义的消息:用来设置步骤信息 */
case MSG_SET_STEP_INFO:
SetWindowAdditionalData (hwnd, (DWORD)lParam);
InvalidateRect (hwnd, NULL, TRUE);
break;
/* 控件自定义的消息:用来设置当前步骤信息 */
case MSG_SET_CURR_STEP:
InvalidateRect (hwnd, NULL, FALSE);
break;
case MSG_DESTROY:
break;
}
return DefaultControlProc (hwnd, message, wParam, lParam);
}
static BOOL RegisterStepControl ()
{
int result;
WNDCLASS StepClass;
StepClass.spClassName = STEP_CTRL_NAME;
StepClass.dwStyle = 0;
StepClass.hCursor = GetSystemCursor (IDC_ARROW);
StepClass.iBkColor = COLOR_lightwhite;
StepClass.WinProc = StepControlProc;
return RegisterWindowClass (&StepClass);
}
static void UnregisterStepControl ()
{
UnregisterWindowClass (STEP_CTRL_NAME);
}
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P><A id=3 name=3><SPAN class=atitle2>3
控件子类化</SPAN></A><BR>采用控件类和控件实例的结构,不仅可以提高代码的可重用性,而且还可以方便地对已有控件类进行扩展。比如,在需要建立一个只允许输入数字的编辑框时,就可以通过重载已有编辑框控件类而实现,而不需要重新编写一个新的控件类。在
MiniGUI 中,这种技术称为子类化或者窗口派生。子类化的方法有三种:</P>
<OL class=n01>
<LI>一种是对已经建立的控件实例进行子类化,子类化的结果是只影响这一个控件实例;
<LI>一种是对某个控件类进行子类化,将影响其后创建的所有该控件类的控件实例;
<LI>最后一种是在某个控件类的基础上新注册一个子类化的控件类,不会影响原有控件类。在 Windows 中,这种技术又称为超类化。
</LI></OL>
<P>在 MiniGUI 中,控件的子类化实际是通过替换已有的窗口过程实现的。清单 3
中的代码就通过控件类创建了两个子类化的编辑框,一个只能输入数字,而另一个只能输入字母:</P>
<P>清单 3 控件的子类化</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>#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);
}
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P><A id=4 name=4><SPAN class=atitle2>4 对话框和对话框模板</SPAN></A><BR>在 MiniGUI
中,对话框是一类特殊的主窗口,这种主窗口只关注与用户的交互――向用户提供输出信息,但更多的是用于用户输入。对话框可以理解为子类化之后的主窗口类。它针对对话框的特殊性(即用户交互)进行了特殊设计。比如用户可以使用
TAB 键遍历控件、可以利用 ENTER 键表示默认输入等等。在 MiniGUI
当中,在建立对话框之前,首先需要定义一个对话框模板,该模板中定义了对话框本身的一些属性,比如位置和大小等等,同时定义了对话框中所有控件的初始信息,包括位置、大小、风格等等。在
MiniGUI 中,用两个结构来表示对话框模板(src/window.h):</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>1172 typedef struct
1173 {
1174 char* class_name; // control class
1175 DWORD dwStyle; // control style
1176 int x, y, w, h; // control position in dialog
1177 int id; // control identifier
1178 const char* caption; // control caption
1179 DWORD dwAddData; // additional data
1180
1181 DWORD dwExStyle; // control extended style
1182 } CTRLDATA;
1183 typedef CTRLDATA* PCTRLDATA;
1184
1185 typedef struct
1186 {
1187 DWORD dwStyle; // dialog box style
1188 DWORD dwExStyle; // dialog box extended style
1189 int x, y, w, h; // dialog box position
1190 const char* caption; // dialog box caption
1191 HICON hIcon; // dialog box icon
1192 HMENU hMenu; // dialog box menu
1193 int controlnr; // number of controls
1194 PCTRLDATA controls; // poiter to control array
1195 DWORD dwAddData; // addtional data, must be zero
1196 } DLGTEMPLATE;
1197 typedef DLGTEMPLATE* PDLGTEMPLATE;
1198
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P>结构 CTRLDATA 用来定义控件,DLGTEMPLATE 用来定义对话框本身。在程序中,应该首先利用 CTRLDATA
定义对话框中所有的控件,并用数组表示。控件在该数组中的顺序,也就是对话框中用户按 TAB
键时的控件切换顺序。然后定义对话框,指定对话框中的控件数目,并指定 DLGTEMPLATE 结构中的 controls
指针指向定义控件的数组。如清单 4 所示。</P>
<P>清单 4 对话框模板的定义</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>DLGTEMPLATE DlgInitProgress =
{
WS_BORDER | WS_CAPTION,
WS_EX_NONE,
120, 150, 400, 130,
"VAM-CNC 正在进行初始化,
0, 0,
3, NULL,
0
};
CTRLDATA CtrlInitProgress [] =
{
{
"static",
WS_VISIBLE | SS_SIMPLE,
10, 10, 380, 16,
IDC_PROMPTINFO,
"正在...",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -