[翻译]-Windows CE 程序设计 (3rd 版)--5.2 公共控件(部分)

翻译 tellmenow


Windows CE的基本目标定位--小型个人生产力工具--在驱动着公共控件的需求。日程和任务管理应用程序中频繁用到时间和日期的需求导致在控件中包括了日期和时间选择控件以及日历控件。个人生产力工具的小屏幕促成了节省空间的命令条。命令条控件和用于IE3.0的rebar控件结合产生了命令带控件。命令带控件为位于Windows CE应用程序顶部的菜单、按钮和其它控件提供了更多的空间。

最后是Pocket PC开发者所熟悉的菜单控件。在Windows CE.NET 4.2中,它被加到了Windows CE公共控件中。我在讨论完命令条控件和命令带控件后,会谈到菜单控件。

命令条
简单地讲,命令条控件将菜单和工具条组合到了一起。这个组合是很有价值的,因为菜单和工具条组合到一行中可以节省空间受限的Windows CE显示器的屏幕空间。对程序员来说,命令条就像一个带有很多帮助函数的工具条,使公共控件编程变的轻而易举。当您使用命令条的时候,除了可以使用命令条函数外,您还可以使用许多工具条消息。图5-1中展示了一个带有命令条的窗口。
图5-1(略):带有命令条的窗口。

创建命令条
您可以通过几步操作来创建命令条,每步都由一个特别的函数来定义。先创建命令条,再加入菜单、按钮、其它控件以及工具提示,最后,添加关闭和帮助按钮到命令条的右侧。

通过调用CommandBar_Create函数来开始创建命令条,该函数原型如下:
HWND CommandBar_Create (HINSTANCE hInst, HWND hwndParent, int idCmdBar);
函数需要程序的实例句柄,父窗口句柄以及控件的ID。如果创建成功,函数返回新创建的命令条控件的句柄。对应用程序来说,光秃秃的命令条并没有多少用处,还需要加入菜单和一些按钮来使它变的有用。

命令条菜单
您可以通过调用下面两个函数之一来给命令条添加菜单。第一个函数是
BOOL CommandBar_InsertMenubar (HWND hwndCB, HINSTANCE hInst, WORD idMenu, int iButton);
头两个参数是命令条句柄和应用程序的实例句柄。idMenu是要被装载到命令条的菜单的资源ID。最后一个参数是紧靠菜单左边的按钮的索引。因为Windows CE规范中指定菜单应该再命令条的左端,所以该参数应该设置为0,表示所有按钮都在菜单右边。

CommandBar_InsertMenubar函数的缺点是它要求从资源中加载菜单。您不能在运行时配置菜单。当然,通过装载一个虚拟菜单,并使用不同的菜单函数来操作菜单的内容,是可能达到这个目的的,但这里有一个更简单的方法:
BOOL CommandBar_InsertMenubarEx (HWND hwndCB, HINSTANCE hInst, LPTSTR pszMenu, int iButton);
函数CommandBar_InsertMenubarEx中,除了第三个参数pszMenu外,其它参数都和CommandBar_InsertMenubar 中的类似。该参数要么是菜单资源的名字,要么是程序先前创建的菜单的句柄。如果pszMenu是菜单句柄,那么hInst参数应该是NULL。

一旦菜单被装载进命令条,就可以在任何时候通过如下函数来被检索菜单句柄:
HMENU CommandBar_GetMenu (HWND hwndCB, int iButton);
第二个参数iButton是紧靠菜单左侧的按钮的索引。这种机制提供了在命令条上识别多个菜单的能力。然而,根据给出的WINDOWS CE设计规范,用户在命令条上只能看到一个菜单。有了菜单句柄,您就可以有许多可用的菜单函数来操纵菜单的结构了。

如果应用程序要修改命令条上的菜单,应用程序必须调用
BOOL CommandBar_DrawMenuBar(HWND hwndCB,int iButton);
它将强迫重绘命令条上的菜单。这里的参数又一次使用了命令条的句柄和菜单左侧按钮的索引。在WINDOWS CE中,您必须使用CommandBar_DrawMenuBar,而不是用在其它的WINDOWS版本中重绘菜单的标准函数DrawMenuBar。

命令条按钮
给命令条增加按钮的过程需要两步,这和给工具条增加按钮的过程类似。首先必须给命令条增加用于按钮的位图图片。其次增加按钮,每个按钮对应先前加入的位图列表里的一个图片。

命令条在一个内部图片列表中维护按钮的位图列表。位图可以一次一个的增加到图象列表中或者将一组图象包含在一个长而且狭窄的位图中。例如,对一个包含了4个16*16像素图象的位图来说,其尺寸将是64*16像素。图5-2显示了给位图图象的布局。

图5-2:包含4个16*16像素图象的位图

装载一个位图可以通过下面的函数来完成。
int CommandBar_AddBitmap (HWND hWndCB, HINSTANCE hInst, int idBitmap, int iNumImage, int iImageWidth, int iImageHeight);
头两个参数和以往的命令条函数一样,是命令条句柄和可执行程序的实例句柄。第三个参数,idBitmap,是位图图象的资源ID。第四个参数iNumImages是加载的位图中图象的数量。只要需要,可以多次调用CommandBar_AddBitmap将多张位图加载到同一个命令条中。最后两个参数是图象的尺寸,都设置为16。

有两个预定义的位图提供了许多通常用在命令条和工具条中的图象。通过将CommandBar_AddBitmap中的hInst设置为HINST_COMMCTRL,将idBitmap设置为IDB_STD_SMALL_COLOR或IDB_VIEW_SMALL_COLOR,您可以装载这两个位图。图5-3展示了这两个位图中包含的图象。第一行的按钮包含了来自标准位图的图象,而第二行按钮包含了标准视窗中的位图。
图5-3:由公共控件DLL提供的两个标准位图中的图象。

这些图象的索引值定义在CommCtrl.h中,所以您不需要知道它们在位图中的确切顺序。这些常量定义如下:
访问标准位图的常量定义
STD_CUT Edit/Cut button image
STD_COPY Edit/Copy button image
STD_PASTE Edit/Paste button image
STD_UNDO Edit/Undo button image
STD_REDOW Edit/Redo button image
STD_DELETE Edit/Delete button image
STD_FILENEW File/New button image
STD_FILEOPEN File/Open button image
STD_FILESAVE File/Save button image
STD_PRINTPRE Print preview button image
STD_PROPERTIES Properties button image
STD_HELP Help button (Use Commandbar_Addadornments function to add a help button to the command bar.)
STD_FIND Find button image
STD_REPLACE Replace button image
STD_PRINT Print button image

访问标准视窗中位图的常量定义
VIEW_LARGEICONS View/Large Icons button image
VIEW_SMALLICONS View/Small Icons button image
VIEW_LIST View/List button image
VIEW_DETAILS View/Details button image
VIEW_SORTNAME Sort by name button image
VIEW_SORTSIZE Sort by size button image
VIEW_SORTDATE Sort by date button image
VIEW_SORTTYPE Sort by type button image
VIEW_PARENTFOLDER Go to Parent folder button image
VIEW_NETCONNECT Connect network drive button image
VIEW_NETDISCONNECT Disconnect network drive button image
VIEW_NEWFOLDER Create new folder button image

加载到命令条中的图象是按它们在图象列表中的索引进行引用的。例如,如果加载的位图包含5个图象,要引用位图中第四个图象,则其基于0的索引值是3。

如果通过多次调用CommandBar_AddBitmap将多个位图图象集加到命令条中的话,将前面的图象数加上图象在当前列表中的索引,即为当前图象的引用值。例如,通过两次调用CommandBar_AddBitmap加入了两个图象集,其中第一次加入的是5个图象,第二次加入的是4个图象,那么要引用第二个图象集中的第三个图象,需要用第一个图象里的图象总数(5)加上对第2个位图的索引(2),得到引用为7。

一旦加载了位图,就可以通过下面两个函数之一来加载按钮。
第一个函数是:
BOOL CommandBar_AddButtons ( HWND hWndCB, UINT uNumButtons, LPTBBUTTON lpButtons);
CommandBar_AddButtons可以一次就给命令条增加一系列按钮。该函数传入一个按钮数量和一个指向TBBUTTON结构数组的指针。数组中的每个元素描述一个按钮。TBBUTTON结构定义如下:
typedef struct {
int iBitmap;
int idCommand;
BYTE fsState;
BYTE fsStyle;
DWORD dwData;
int iString;
} TBBUTTON;
iBitmap设置为按钮使用的位图图象。也就是我刚解释的图象列表中基于0的索引。第二个参数是按钮的命令ID。当用户点击按钮的时候,通过WM_COMMAND消息,该ID被发送到父窗口。

fsState域则定义了按钮的初始状态。该域所允许的值如下:
TBSTATE_ENABLED 按钮有效。如果没有指定该标志,按钮将失效并变灰。
TBSTATE_HIDDEN 按钮在命令条上不可见。
TBSTATE_PRESSED 按钮显示为下压状态。

TBSTATE_CHECKED 按钮初始被选中。只有当按钮是TBSTYLE_CHECKED风格时该状态才可用。
TBSTATE_INDETERMINATE 按钮变灰。
最后一个标志TBSTATE_WRAP,尽管其在文档中有定义,但在命令条中它是无效的。该标志用在工具条超过一行而折行时。

fsStyle指定了按钮的初始风格,用来表明按钮如何响应动作。按钮可以定义为标准下压按钮,复选框按钮,下拉列表框,以及类似单选框的复选框,此时只允许一组中的一个按钮被选择。对fsStyle来说可能的标志如下:
TBSTYLE_BUTTON 标准下压按钮
TBSTYLE_CHECK 复选框,每次用户点该按钮时,在选择和取消选择之间切换。
TBSTYLE_GROUP 定义一组按钮的开始按钮。

TBSTYLE_CHECKGROUP 表示是一组复选框中的一个,并且行为和单选框类似,每次只能有一个按钮被选择。
TBSTYLE_DROPDOWN 下拉列表框。

TBSTYLE_AUTOSIZE 按钮尺寸取决于按钮的文本。
TBSTYLE_SEP 定义了一个分隔条,在按钮之间插入一小块空间。

TBBUTTON结构中的dwData域里是应用程序定义的值。通过使用TB_SETBUTTONINFO和TB_GETBUTTONINFO消息,应用程序可以设置和查询该值。iString则定义了在包含按钮文字的命令条字符数组中的索引。该域也可以添充为指向按钮文本的字符串的指针。

给命令条增加按钮的另一个函数如下:
BOOL CommanBar_InsertButton (HWND hwndCB, int iButton, LPTBBUTTON lpButton);

该函数将一个按钮插到命令条中iButton所对应的按钮的左边。除了指向单个TBBUTTON结构的lpButton外,该函数的参数同CommandBar_AddButtons类似。iButton给出了新按钮在命令条上的位置。

使用命令条按钮
除了下拉按钮外,当用户按一个命令条按钮时,命令条都会给其父窗口发送一个WM_COMMAND消息。所以处理命令条上的按钮点击就像处理菜单命令一样。实际上,因为命令条上许多按钮都有等价的菜单命令,所以习惯上为按钮和同功能的菜单使用相同的命令ID号,这样可以减少对命令条按钮进行特定的处理的需求。

命令条会维护单个复选框和一组复选框按钮的选择状态。当按钮被加到命令条中以后,可以使用下面两个消息来查询或者设置它们的状态:TB_ISBUTTONCHECKED和TB_CHECKBUTTON。(前缀TB_暗示了命令条和工具条控件之间的密切关系。)把要查询的按钮的ID放到参数wParam中,将TB_ISBUTTONCHECKED消息按下面的方式发送出去:
fChecked = SendMessage (hwndCB, TB_ISBUTTONCHECKED, wID, 0);
hwndCB是包含按钮的命令条的句柄。该函数如果返回值非零,表示按钮被选择了。要将按钮设置成选择状态,可以给命令条发送一个TB_CHECKBUTTON消息,方法如下:
SendMessage (hwndCB, TB_CHECKBUTTON, wID,TRUE);
要取消选择,只要将TRUE换成FALSE即可。

使按钮失效
Windows CE允许您很容易的修改命令条或者工具条上失效按钮的外观。命令条和工具条维护两个图象列表:先前讲述过的标准图象列表和一个失效图象列表,该列表用来存储用于失效按钮的图象。

要使用该特性,您需要为失效按钮创建和装载第2个图象列表。而最容易的方式就是用谈论CommandBar_AddBitmap时描述的技术,为按钮的普通状态创建一个图象列表。(可以使用TB_LOADIMAGES消息来装载工具条中的图象列表。)一旦完成了图象列表,只要简单的复制原始图象列表,并修改图象列表中的位图,为原始位图创建一个失效副本即可。接下来将新的图象列表装载回命令条或者工具条即可。下面的代码片段展示了如何完成这些工作的:
HBITMAP hBmp, hMask;
HIMAGELIST hilDisabled, hilEnabled;

// Load the bitmap and mask to be used in the disabled image list.
hBmp = LoadBitmap (hInst, TEXT ("DisCross"));
hMask = LoadBitmap (hInst, TEXT ("DisMask"));

// Get the standard image list and copy it.
hilEnabled = (HIMAGELIST)SendMessage (hwndCB, TB_GETIMAGELIST, 0, 0);
hilDisabled = ImageList_Duplicate (hilEnabled);

// Replace one bitmap in the disabled list.
ImageList_Replace (hilDisabled, VIEW_LIST, hBmp, hMask);

// Set the disabled image list.
SendMessage (hwndCB, TB_SETDISABLEDIMAGELIST, 0, (LPARAM) hilDisabled);

代码中首先装载了一个位图和一个掩码位图,它们将用于替换失效图象列表中的位图。通过给命令条发送TB_GETIMAGELIST消息,可以获得当前的图象列表,之后用ImageList_Duplicate来复制一个图象列表。最后用之前装载的位图来替换图象列表中的相应图象即可。

本例仅替换了一个位图,但在实际应用中可以替换许多位图。如果所以有的位图都被替换,那么从头创建一个失效的图象列表可能比复制一个标准图象列表再替换其中的一些位图会更容易一些。一旦新的图象列表被创建完成,您可以通过发送TB_SETDISABLEDIMAGELIST消息将列表装载进命令条中。上面的代码对Windows CE下的命令条一样有效。

下拉按钮
同命令条上的标准按钮相比,下拉按钮显得更复杂一些。对用户来说,它就是一个按钮,当被按下的时候,会显示一个列表项来让用户选择。对程序员来说,下拉按钮实际上就是按钮和菜单的组合,当用户点击按钮的时候会显示一个菜单。不幸地是,命令条对下拉按钮支持有限,只提供了修改按钮外观的功能以表示是一个下拉按钮以及当用户点击按钮时会发送特定通知的功能。另外,是由应用程序决定如何显示菜单的。

通过发送带TBN_DROPDOWN通知码的WM_NOTIFY消息,用户点击下拉按钮的通知将会发送到命令条的父窗口中。当父窗口接收到TBN_DROPDOWN通知后,它必须立即在通知消息中标识的下拉按钮下创建一个弹出菜单。菜单由父窗口使用适当的选项来填充。当有菜单项被选择时,菜单将发送WM_COMMAND消息,表示菜单项被选择了并且菜单即将消失。为了更容易理解如何处理下拉按钮通知,可以浏览以下处理TBN_DROPDOWN通知的过程:
LRESULT DoNotifyMain (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
LPNMHDR pNotifyHeader;
LPNMTOOLBAR pNotifyToolBar;
RECT rect;
TPMPARAMS tpm;
HMENU hMenu;

// Get pointer to notify message header.
pNotifyHeader = (LPNMHDR)lParam;

if (pNotifyHeader->code == TBN_DROPDOWN) {

// Get pointer to toolbar notify structure.
pNotifyToolBar = (LPNMTOOLBAR)lParam;

// Get the rectangle of the drop-down button.
SendMessage (pNotifyHeader->hwndFrom, TB_GETRECT,
pNotifyToolBar->iItem, (LPARAM)&rect);

// Convert rect to screen coordinates. The rect is
// considered here to be an array of 2 POINT structures.
MapWindowPoints (pNotifyHeader->hwndFrom, HWND_DESKTOP,
(LPPOINT)&rect, 2);

// Prevent the menu from covering the button.
tpm.cbSize = sizeof (tpm);
CopyRect (&tpm.rcExclude, &rect);

// Load the menu resource to display under the button.
hMenu = GetSubMenu (LoadMenu (hInst, TEXT ("popmenu")),0);

// Display the menu. This function returns after the
// user makes a selection or dismisses the menu.
TrackPopupMenuEx (hMenu, TPM_LEFTALIGN | TPM_VERTICAL,
rect.left, rect.bottom, hWnd, &tpm);
}
return 0;
}

当代码判断出是TBN_DROPDOWN通知后,首先要做的就是获取下拉按钮的矩形。获取该矩形是为了使下拉菜单能被立即定位到按钮下方。要达到该目的,程序会发送TB_GETRECT消息给命令条,其中参数wParam是下拉按钮的ID,参数lParam是指向矩形结构的指针。

因为返回的矩形是基于父窗口的坐标,而弹出菜单是屏幕坐标,所以必须进行坐标转换。这可以使用以下函数来完成:
MapWindowPoints (HWND hwndFrom, HWND hwndTo, LPPOINT lppoints, UINT cPoints);
第一个参数是原始坐标的窗口句柄。第二个参数是将要转换到的坐标所在的窗口句柄。第三个参数是指向将被转换的坐标点数组的指针。最后一个参数是数组中点的数量。在我所展示的程序里,窗口句柄分别是命令条句柄和桌面窗口句柄。

一旦矩形被转换成桌面坐标,就可以创建弹出菜单或者和上下文相关的菜单了。要这样做,您首先需要从资源中装载菜单并调用TrackPopupMenuEx来显示菜单。如果您能回想起前面章节中对TrackPopupMenuEx的讨论,那么就会知道TPMPARAMS结构包含一个不会被菜单显示所覆盖的矩形。对次,矩形被设置成下拉按钮的大小,这样按钮就不会弹出菜单所覆盖了。fuFlags中则包含了许多值,用来定义菜单的位置。对下拉按钮来说,只需要TPM_VERTICAL标志。如果TPM_VERTICAL被设置,菜单会尽可能的为非覆盖矩形保留更多的水平区域。TrackPopupMenuEx函数会一直等到菜单项被选择或者当用户在屏幕的其它地方点击后菜单消失时才会返回。(待续)

你可能感兴趣的:(编程,windows,浏览器,配置管理,Go)