1.与排版有关的两个消息:WM_SIZE和WM_SETTINGCHANGE消息。我们需要在这两个消息里处理排版有关的操作。
(1). 如果窗口大小改变,窗口将收到 WM_SIZE 通知。WM_SIZE 消息的 lParam 参数的低位字指定了客户端区域的新宽度,高位字指定了客户端区域的新高度。应用程序应识别窗口大小的改变,并相应地更新窗口布局。此外,也应重新确定所包 含任何子窗口的布局。
(2).WM_SIZE和WM_SETTINGCHANGE有什么区别呢?如果应用程序没有全屏窗口,它收不到 WM_SIZE 通知。相反,它应在 wParam 参数设置为SETTINGCHANGE_RESET时监听 WM_SETTINGCHANGE消息。
(3). 如果应用程序有顶层窗口,或使用 SHHandleWMSettingChange、SHInitDialog 和 SHFullScreen 方法创建了窗口,它会同时收到 WM_SIZE 和 WM_SETTINGCHANGE 消息。但是,如果应用程序创建了子窗口,子窗口收不到 WM_SIZE 消息,即使子窗口是全屏窗口。
备注:如果窗口的上、左、右坐标在工作区域边界之上或之外,该窗口被认为是全屏窗口。工作区域是标题栏下的整个屏幕区域。
代码示例如下:
switch (uMessage) {
case WM_SIZE:
// 重新计算所有子窗口的布局;重新设置
// 列出视图和编辑框的大小,重新确定按钮、
// 静态文字和其他控件的位置。
break;
case WM_SETTINGCHANGE:
if (SETTINGCHANGE_RESET == wParam) {
// 屏幕方向改变。此时
// 执行 WM_SIZE 不能执行的处理,
// 如重新调整全屏子窗口的大小,对
// 顶层窗口调用 MoveWindow 等等。
// 如果不需要处理 WM_SETTINGCHANGE 消息,可以
// 忽略它。
}
break;
}
2.那我们怎样使用这两个消息排版呢?
比如可以使用RelayoutDialog,它可帮助重新设置、重新定位对话框中的子控件。例如,假设对话框有两个对话模板,一个用于横向,一个用于竖向。如果这两个模板中的控件相同,且有相同的控件 ID,则可使用下列代码作为WM_SIZE处理程序:
case WM_SIZE:
RelayoutDialog(g_hInst, hDlg, InWideMode() ? MAKEINTRESOURCE
(IDD_TOOLS_OPTIONS_1_WIDE) : MAKEINTRESOURCE(IDD_TOOLS_OPTIONS_1));
注意: 定义为 IDC_STATIC 的控件具有相同的控件 ID,所以如果有多个 IDC_STATIC控件,应当把它们重命名为 IDC_STATIC_1、IDC_STATIC_2等。
如果静态控件在新布局中也发生了变换,RelayoutDialog 会同时更新静态控件的文本和位图。
3.Windows Mobile 6.0 SDK中有几个相关的Samples,在这里介绍下。
Crossword例子中的LandscapeAware部分向你示范了怎样让你的应用程序支持横竖屏。
(1).首先用320*320大小的背景图片替换掉原来的240*320的图片,这样横竖屏切换时,只需一张背景图片即可保持统一的风格。OnPaint中绘图函数修改为:
BitBlt(hDC, 0, 0, 320, 320, hMemDC, 0, 0, SRCCOPY);
(2).定义一个判断当前横竖屏的函数:
BOOL InWideMode()
{
int height = GetSystemMetrics(SM_CYSCREEN);
return (height < 320) ? TRUE : FALSE;
}
也可以使用DeviceResolutionAware.h中的函数。
(3).使用判断载入资源,比如:
RECT& r = InWideMode() ? rWideMode : rTallMode;
(4).在WM_SIZE中调整受到横竖屏切换影响的空间的位置和大小,比如:
MoveWindow(hEditBox, 8, 4, nWidth - 70, 20, TRUE);
MoveWindow(hEnterButton, nWidth - 57, 4, 50, 20, TRUE);
在对话框的WM_SIZE中处理屏幕模式的适应,如:
DRA::RelayoutDialog(g_hInst, hDlg,InWideMode() ?
MAKEINTRESOURCE(IDD_TOOLS_OPTIONS_1_WIDE) :
MAKEINTRESOURCE(IDD_TOOLS_OPTIONS_1));
Crossword例子中的HidpiAware部分示范怎样适应高分辨率的屏幕,并且支持上个例子的横竖屏功能。
很简单,将代码中直接出现数字的代码:
MoveWindow(hEditBox, 8, 4, nWidth - 70, 20, TRUE);
改成:
MoveWindow(hEditBox, SCALEX(8), SCALEY(4), nWidth - SCALEX(70), SCALEY(20), TRUE);
在DeviceResolutionAware.h头文件中定义的SCALEX原型:
inline int SCALEX(int argX, int nLogPixelsX = LogPixelsX())
{
return HIDPIMulDiv(argX, nLogPixelsX, HIDPI);
}
UILayout例子介绍了微软提供的用于界面布局的ScreenLib工具类。 比如:
//根据屏幕情况优化高度
CScreenLib::OptimizeHeight(m_hWnd, IDC_EDIT_MESSAGE);
//根据屏幕情况优化宽度
CScreenLib::OptimizeWidth(m_hWnd, 3, //受影响的控件个数 IDC_STATIC_SENDTO, //控件ID IDC_COMBO_SENDTO, IDC_EDIT_MESSAGE);
在WM_SIZE消息处理中调整控件的大小以适应横竖屏,在WM_SETTINGCHANG消息处理中添加当SIP变化时对控件大小的调整。
4.关于Windows Mobile本地代码开发中界面布局的总结。
ScreenLib 和 DeviceResolutionAware.h 是界面布局中的两个方案。
ScreenLib 提供了一组帮助函数,用于对齐屏幕上的元素。例如,您可以使用 DockControl 函数将给定控件停靠到屏幕某个边缘或所有四个边缘来填充客户端区域。OptimizeWidth 和 OptimizeHeight 函数将某个控件(或多个控件 — 对于 OptimizeWidth 函数)与显示器对齐并调整其大小,左右或上下分别留出一小块边距。提供的其他函数可用于对齐控件和将一组控件调整为相同大小。在这些函数中,当大量使用基 于窗体的应用程序时,ScreenLib 可能最有用。
DeviceResolutionAware.h 弥补了 ScreenLib 的不足,并提供了有助于构建更复杂的自适应应用程序的 20 多个函数和宏。比如:
GetDisplayMode:确定显示当前被配置为纵向、横向还是方形。
RelayoutDialog:修改对话框的布局以符合指定的对话框资源。
StretchIcon/StretchBitmap:将图标或位图拉伸到指定的大小。
ImageList_LoadImage:根据指定的位图创建图像列表,自动缩放图像以适应位图和屏幕 DPI值方面的差异。
5.程序中的字体和字体大小。
应该让用户可以从控制面板中选择默认的字体大小。所以避免将ListView, TreeView, ListBox, RichEdit等控件的字体大小设置死了。你可以使用SHGetUIMetrics获得用户选择的默认值来设置你应用程序中的字体大小。
另外当你的应用程序启动时或用户改变字体大小(侦听SH_UIMETRIC_CHANGE消息通知)的设置时,你应该检查默认字体大小。
而RadioButton, Label, TextBox, and CheckBox等控件应该有固定大小的字体,不应该随着默认字体设置的变化而变化。
“Create Compatible User Interfaces”原文:
Avoid hard-coding font sizes for controls such as ListView, TreeView, ListBox, and RichEdit. The user can select a default text size by using the Screen command in Control Panel.
Query for the user-selected default text size using the SHGetUIMetrics
function, and then set the fonts in the application to that size, creating a
consistent experience. Check the default text size when the application starts and when the user changes the default size. The application can detect
when the user changes the default font setting by listening for the
SH_UIMETRIC_CHANGE notification.
Use static font sizes for dialog controls. Controls such as RadioButton, Label, TextBox, and CheckBox should have a fixed size that does not change with
the device default text size setting.
6.合理设计软键。
左软键应该是简单的命令健(比如“确定”),不应该弹出个菜单。如果右软键是个菜单,菜单里的选项应该是最常用的,从上到下按常用顺序排列,第一项默认高亮显示。避免再出现子菜单。
“Create Compatible User Interfaces”原文:
The left soft key must be a single command, not a menu. It should be the default or most frequent choice. For example, if a dialog box appears, the left soft key might be the command Done, which would close the dialog box and return the user to the application.
If the right soft key is a menu, the top command in the menu should be the most frequently used command. By default, when the right soft key menu appears, the top command is highlighted.
On the right soft key, avoid using submenus that are more than two levels deep.
7.界面颜色。
注意与系统的颜色保持统一,所以当你使用诸如GDI绘制文字时应该查询当前系统的颜色。
“Create Compatible User Interfaces”原文:
All Windows Forms controls automatically adapt to the current theme. However, if you use GDI to draw text manually, query the system for the colors associated with various UI elements so that the application will look consistent with the operating system and remain usable with all themes.
8.程序的图标。
我们在资源中包含不同分辨率下的程序图标,并且在程序运行时候检测以决定加载。
合适的图标和不合适的图标:
![](http://i.msdn.microsoft.com/Bb677144.46c647f9-6570-4ecd-858c-3a3ff9ca81d2%28en-us,MSDN.10%29.gif)
Windows Mobile 6 Professional/Windows Mobile 6 Classic各分辨率对应的合适图标:
Screen Dimensions | DPI | Orientation | Small Icon Size | Large Icon Size |
240 x 320 | 96 | PL | 16 x 16 | 32 x 32 |
480 x 640 (VGA) | 192 | PL | 32 x 32 | 64 x 64 |
240 x 240 | 96 | S | 16 x 16 | 32 x 32 |
480 x 480 (VGA) | 192 | S | 32 x 32 | 64 x 64 |
320 x 320 | 128 | S | 21 x 21 | 43 x 43 |
9 .避免使用位图 。
同一张位图在 不同分辨率的设备上会出现如下问题:
![](http://i.msdn.microsoft.com/Bb677141.8b464d06-f69d-4458-a488-0034917f9163%28en-us,MSDN.10%29.gif)
![](http://i.msdn.microsoft.com/Bb677141.0b301ff1-3a38-41bc-acd2-4a4dec6ea980%28en-us,MSDN.10%29.gif)
而以下设计比较好:
![](http://i.msdn.microsoft.com/Bb677141.10980d7a-4af3-47c5-abc5-6c27b773525b%28en-us,MSDN.10%29.gif)
![](http://i.msdn.microsoft.com/Bb677141.33474968-f999-4fa3-81a9-65637f04443e%28en-us,MSDN.10%29.gif)
另外还应该考虑一些潜在的问题。
10.更多参考。
微软开发人员中心文档:开发能够识别 DPI 的应用程序。
微软开发人员中心文档: Create Compatible User Interfaces 。
Windows Mobile 6 Documentation > Shell, GWES, and User Interface > Shell > Shell OS Design Development > Screen Rotation for Windows Mobile Powered Devices > Developing Screen Orientation Aware Applications
Introducing Screenlib (附带一个讲解的视频,使用的是MFC)
SDK例子:Samples/PocketPC/CPP/win32/Crossword
Samples/Common/CPP/Win32/UILayout