📄 基于 linux 和 minigui 的嵌入式系统软件开发指南(二).htm
字号:
<TD>其他</TD>
<TD>可以利用 PostSyncMessage 函数跨线程发送消息,并等待消息的处理结果</TD>
<TD>不能使用 PostSyncMessage、SendAsynMessage
等消息。</TD></TR></TBODY></TABLE><BR><BR>
<P><A id=5 name=5><SPAN class=atitle2>5 窗口的建立和销毁</SPAN></A></P>
<P><SPAN class=atitle3>5.1 窗口的建立</SPAN><BR>我们知道,MiniGUI 的 API 类似 Win32 的
API。因此,窗口的建立过程和 Windows 程序基本类似。不过也有一些差别。首先我们回顾一下 Windows 应用程序的框架:</P>
<OL class=n01>
<LI>在 WinMain () 中创建窗口,使用以下步骤:创建窗口类、登记窗口类、创建并显示窗口、启动消息循环。
<LI>在 WndProc () 中,负责对发到窗口中的各种消息进行响应。 </LI></OL>在 MiniGUI
中也同样要有这两个函数。不过稍微有点不同。程序的入口函数名字叫MiniGUIMain
(),它负责创建程序的主窗口。在建立主窗口之后,程序进入消息循环。<BR><BR>
<P>在 Win32 程序中,在建立一个主窗口之前,程序首先要注册一个窗口类,然后创建一个属于该窗口类的主窗口。MiniGUI
却没有在主窗口中使用窗口类的概念。在 MiniGUI 程序中,首先初始化一个 MAINWINCREATE 结构,该结构中元素的含义是:</P>
<TABLE cellSpacing=0 cellPadding=5 border=0>
<TBODY>
<TR>
<TD>CreateInfo.dwStyle:</TD>
<TD>窗口风格</TD></TR>
<TR>
<TD>CreateInfo.spCaption:</TD>
<TD>窗口的标题</TD></TR>
<TR>
<TD>CreateInfo.dwExStyle :</TD>
<TD>窗口的附加风格</TD></TR>
<TR>
<TD>CreateInfo.hMenu:</TD>
<TD>附加在窗口上的菜单句柄</TD></TR>
<TR>
<TD>CreateInfo.hCursor:</TD>
<TD>在窗口中所使用的鼠标光标句柄</TD></TR>
<TR>
<TD>CreateInfo.hIcon:</TD>
<TD>程序的图标</TD></TR>
<TR>
<TD>CreateInfo.MainWindowProc:</TD>
<TD>该窗口的消息处理函数指针</TD></TR>
<TR>
<TD>CreateInfo.lx:</TD>
<TD>窗口左上角相对屏幕的绝对横坐标,以象素点表示</TD></TR>
<TR>
<TD>CreateInfo.ty:</TD>
<TD>窗口左上角相对屏幕的绝对纵坐标,以象素点表示</TD></TR>
<TR>
<TD>CreateInfo.rx:</TD>
<TD>窗口的长,以象素点表示</TD></TR>
<TR>
<TD>CreateInfo.by:</TD>
<TD>窗口的高,以象素点表示</TD></TR>
<TR>
<TD>CreateInfo.iBkColor:</TD>
<TD>窗口背景颜色</TD></TR>
<TR>
<TD>CreateInfo.dwAddData:</TD>
<TD>附带给窗口的一个 32 位值</TD></TR>
<TR>
<TD>CreateInfo.hHosting:</TD>
<TD>窗口消息队列所属</TD></TR></TBODY></TABLE><BR><BR>
<P>其中有如下几点要特别说明:</P>
<OL class=n01>
<LI>CreateInfo.dwAddData:在程序编制过程中,应该尽量减少静态变量,但是如何不使用静态变量而给窗口传递参数呢?这时可以使用这个域。该域是一个
32 位的值,因此可以把所有需要传递给窗口的参数编制成一个结构,而将结构的指针赋予该域。在窗口过程中,可以使用
GetWindowAdditionalData 函数获取该指针,从而获得所需要传递的参数。
<LI>CreateInfo.hHosting:该域表示的是将要建立的主窗口使用哪个主窗口的消息队列。使用其他主窗口消息队列的主窗口,我们称为"被托管"的主窗口。当然,这只在
MiniGUI-Threads 版本中有效。
<LI>MainWinProc
函数负责处理窗口消息。这个函数就是主窗口的"窗口过程"。窗口过程一般有四个入口参数,第一个是窗口句柄,第二个是消息类型,第三个和第四个是消息的两个参数。
</LI></OL><BR><BR>
<P>在准备好MAINWINCREATE 结构之后,就可以调用 CreateMainWindow
函数建立主窗口了。在建立主窗口之后,典型的程序将进入消息循环。如下所示:</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>int MiniGUIMain (int args, const char* arg[])
{
MSG Msg;
MAINWINCREATE CreateInfo;
HWND hWnd;
// 初始化 MAINWINCREATE 结构
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;
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_SHOWNORMAL);
// 进入消息循环
while (GetMessage(&Msg, hWnd)) {
TranslateMessage (&Msg);
DispatchMessage(&Msg);
}
MainWindowThreadCleanup (hWnd);
return 0;
}
</CODE>
</PRE></TD></TR></TBODY></TABLE>注意,和 Windows 程序不同的是,在退出消息循环之后,还要调用一个函数,即
MainWindowThreadCleaup 函数。该函数的工作是销毁主窗口的消息队列,一般在线程或者进程的最后调用。<BR><BR>
<P><SPAN class=atitle3>5.2 窗口的销毁</SPAN><BR>要销毁一个主窗口,可以利用 DestroyMainWindow
(hWnd) 函数。该函数将销毁主窗口,但不会销毁主窗口所使用的消息队列,而要使用MainWindowThreadCleaup
最终清除主窗口所使用的消息队列。</P>
<P>一般而言,一个主窗口过程在接收到 MSG_CLOSE 消息之后会销毁主窗口,并调用 PostQuitMessage
消息终止消息循环。如下所示:</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>case MSG_CLOSE:
// 销毁窗口使用的资源
DestroyLogFont (logfont1);
DestroyLogFont (logfont2);
DestroyLogFont (logfont3);
// 销毁子窗口
DestroyWindow(hWndButton);
DestroyWindow(hWndEdit);
// 销毁主窗口
DestroyMainWindow (hWnd);
// 发送 MSG_QUIT 消息
PostQuitMessage(hWnd);
return 0;
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P><A id=6 name=6><SPAN class=atitle2>6
几个重要消息</SPAN></A><BR>在窗口(包括主窗口和子窗口在内)的生存周期当中,有几个重要的消息需要仔细处理。下面描述这些消息的概念和典型处理。</P>
<P><SPAN class=atitle3>6.1 MSG_NCCREATE</SPAN><BR>该消息在 MiniGUI
建立主窗口的过程中发送到窗口过程。lParam 中包含了由 CreateMainWindow 传递进入的 pCreateInfo
结构指针。您可以在该消息的处理过程中修改 pCreateInfo 结构中的某些值。</P>
<P><SPAN class=atitle3>6.2
MSG_SIZECHANGING</SPAN><BR>该消息窗口尺寸发生变化时,或者建立窗口时发送到窗口过程,用来确定窗口大小。wParam
包含预期的窗口尺寸值,而 lParam 用来保存结果值。MiniGUI 的默认处理是,</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>case MSG_SIZECHANGING:
memcpy ((PRECT)lParam, (PRECT)wParam, sizeof (RECT));
return 0;
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P>你可以截获该消息的处理,从而让即将创建的窗口位于指定的位置,或者具有固定的大小,比如在 SPINBOX
控件中,就处理了该消息,使之具有固定的大小:</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>case MSG_SIZECHANGING:
{
const RECT* rcExpect = (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;
}
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
<P><SPAN class=atitle3>6.3
MSG_CHANGESIZE</SPAN><BR>在确立窗口大小之后,该消息被发送到窗口过程,用来通知确定之后的窗口大小。wParam
包含了窗口大小 RECT 的指针。注意应用程序应该将该消息传递给 MiniGUI 进行默认处理。</P>
<P><SPAN class=atitle3>6.4 MSG_SIZECHANGED</SPAN><BR>该消息用来确定窗口客户区的大小,和
MSG_SIZECHANGING 消息类似。wParam 参数包含窗口大小信息,lParam 参数是用来保存窗口客户区大小的 RECT
指针,并且具有默认值。如果该消息的处理返回非零值,则将采用 lParam 当中包含的大小值作为客户区的大小;否则,将忽略该消息的处理。比如在
SPINBOX 控件中,就处理了该消息,并使客户区占具所有的窗口范围:</P>
<TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc
border=1><TBODY>
<TR>
<TD><PRE><CODE>case MSG_SIZECHANGED
{
RECT* rcClient = (RECT*) lPraram;
rcClient->right = rcClient->left + _WIDTH;
rcClient->bottom = rcClient->top + _HEIGHT;
return 0;
}
</CODE>
</PRE></TD></TR></TBODY></TABLE><BR><BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -