WinCE 编程基础
4 窗口 控件和菜单 窗口 控件 菜单
窗口 概述 Windows 显示的每个东西都是一个窗口 窗口之间彼此是相互关联的 它们可以是父子 兄弟或是拥有与被拥有的关系 Windows 支持许多预定义的窗口类, 也称为控件 从简单的按钮到复杂的多行文本编辑器, 控件通过提供一系列预定义的用户界面元素, 简化了程序员的工作 注意 : 不要将这些内置控件同公共控件库提供的复杂控件相混淆 子窗口应用程序创建一个没有父亲的主窗口, 称为顶层窗口 该窗口可能包含有窗口, 称为子窗口 子窗口会被父窗口裁减 也就是说, 子窗口超出父窗口边沿的部分是不可见的 当父窗口被销毁时, 子窗口自动被销毁 当父窗口移动的时候, 子窗口随父窗口一起移动 可使用 CreateWindow 或 CreateWindowsEx 函数来创建子窗口, 要创建子窗口, 需要将 CreateWindow 或 CreateWindowEx 的参数 dwstyle 设置为 WS_CHILD 对在顶层 Windows CE 窗口中没有使用的 hmenu 参数, 可以传一个 ID 用以引用该子窗口
窗口 查找父窗口 HWND GetParent( HWND hwnd ); 函数返回指定窗口 hwnd 的父窗口句柄 如果 hwnd 没有父窗口, 则函数返回 NULL 枚举窗口 HWND GetWindow(HWND hwnd, UINT ucmd); hwnd: 查询窗口的句柄 ; ucmd: 是一个常量, 指出要查询的关系 常量 GW_CHILD, 表示返回窗口第一个子窗口的句柄 GetWindow 是按 Z 坐标顺序来返回窗口的, 所以在这种情况下, 第一个子窗口就是 Z 坐标最高的子窗口 如果窗口没有子窗口, 该函数则返回 NULL 常量 GW_HWNDFIRST 和 GW_HWNDLAST, 按 Z 坐标返回第一个和最后一个窗口 常量 GW_HWNDNEXT 和 GW_HWNDPREV, 按 Z 坐标返回下一个更低和更高的窗口 常量 GW_OWNER: 返回窗口拥有者的句柄
窗口 枚举窗口 ( 续 ) BOOL EnumWindows(WNDENUMPROC lpenumfunc, LPARAM lparam); lpenumfunc: 指向一个回调函数,EnumWindows 为桌面上的每个顶层窗口调用一次该回调函数, 并依次传入每个窗口的句柄 lparam: 应用程序定义的值, 并被传递给枚举函数 该函数比通过 GetWindow 循环来寻找顶层窗口的遍历方式要好, 因为该函数始终返回有效的窗口句柄, 而一个 GetWindow 遍历循环里, 获得的窗口句柄可能在下次调用 GetWindow 之前其对应的窗口就已经被销毁了 但是, 因为 EnumWindows 只对顶层窗口有效, 所以当遍历一系列子窗口时 GetWindow 还是有用武之地的
窗口 查找窗口 FindWindow(LPCTSTR lpclassname, LPCTSTR lpwindowname); 函数通过窗口的类名或者窗口的标题找到窗口 HWND GetDesktopWindow(void); 查找桌面窗口句柄的函数
窗口 获取 / 设置指定窗口信息 LONG GetWindowLong( HWND hwnd, int nindex ); LONG SetWindowLong(HWND hwnd, int nindex, LONG dwnewlong); nindex: 用来使应用程序访问窗口的一些基本参数 GWL_STYLE: 窗口风格标志 GWL_EXSTYLE: 窗口扩展风格标志 GWL_WNDPROC: 指向窗口过程的指针 GWL_ID: 窗口标识 GWL_USERDATA: 应用程序使用的 32 位值对话框窗口还支持下面附加的值 : DWL_DLGPROC: 指向对话框窗口过程的指针 DWL_MSGRESULT: 当对话框函数返回时的返回值 DWL_USER: 应用程序使用的 32 位值 dwnewlong: 指定的替换值
窗口 获取 / 设置指定窗口信息 ( 续 ) 如果函数成功, 返回值是所需的值 ( GetWindowLong )/ 指定的原值 (SetWindowLong) 如果函数失败, 返回值为 0 若想获得更多错误信息, 请调用 GetLastError 函数 改变风格标志 在窗口被创建后, 通过改变其窗口风格位, 可以改变窗口的默认行为和外观 任何修改窗口外观的风格标志被改变后, 习惯上都要通过调用 SetWindowPos 来强制系统重新绘制窗口的非客户区
窗口 改变风格标志 ( 续 ) BOOL SetWindowPos(HWND hwnd, HWND hwndinsertafter, int X, int Y, int cx, int cy, UINT uflags); hwnd: 即将改变的窗口句柄 hwndinsertafter: 可选 允许设置窗口的 Z 坐标 该参数要么是窗口句柄, 要么是下面 4 个标志之一, 用来放置窗口到 Z 坐标顶部或底部 标志位如下所示 : HWND_BOTTOM: 窗口在桌面上所有窗口之下 ; HWND_TOP: 窗口在所有窗口的顶部 ; HWND_TOPMOST: 窗口始终放置在其它窗口顶部, 即使该窗口处于非活动窗口 HWND_NOTTOPMOST: 窗口位于其它非置顶窗口 (nontopmost windows) 之上, 但没有标记为置顶窗口 (topmost window), 这样当有另一个窗口成为活动窗口时, 该窗口可以被覆盖
窗口 改变风格标志 ( 续 ) BOOL SetWindowPos(HWND hwnd, HWND hwndinsertafter, int X, int Y, int cx, int cy, UINT uflags); X Y cx 和 cy: 指定窗口的位置和大小 uflags: 包含一个或多个标志位, 用来描述要完成的任务 这些标志如下所示 : SWP_NOMOVE: 不移动窗口 SWP_NOSIZE: 不改变窗口大小 SWP_NOZORDER: 不设置窗口 Z 坐标 SWP_NOACTIVATE: 如果设置了 Z 坐标, 则不激活窗口 SWP_DRAWFRAME: 重绘非客户区 SWP_FRAMECHANGED: 重新计算非客户区, 并重新绘制 另有两个标志, 可以显示和隐藏窗口 :SWP_SHOWWINDOW 和 SWP_HIDEWINDOW 但调用 ShowWindow 函数来显示和隐藏窗口会更容易一些
窗口 改变风格标志 ( 续 ) 如, 在风格位改变后, 可用如下操作来强制重绘框架 : SetWindowPos (hwnd, 0, 0, 0, 0,0, SWP_NOMOVE SWP_NOSIZE SWP_NOZORDER SWP_FRAMECHA NGED); 再如, 程序启动后, 通过下列语句, 改变位置和大小 : SetWindowPos(hWnd, 0,10, 20, 200, 250,SWP_NOZORDER);
窗口 窗口子类化 SetWindowLong 的另一个用途是子类化一个窗口 即改变一个窗口的窗口过程 子类化的典型应用是修改窗口控件的行为 窗口子类化的过程 : 1) 创建一个窗口过程来为被子类化的窗口提供新功能 2) 为该窗口调用 GetWindowLong 来获得并保存一个指向其初始窗口过程的指针 3) 调用 SetWindowLong 函数, 将窗口实例的窗口过程设置成新的窗口过程 这样, 新的窗口过程就开始接收发给该窗口的消息了 任何没有被新窗口过程响应的消息都可通过调用 CallWindowProc 传递给 2) 中旧的窗口过程 原型 : LRESULT CallWindowProc( WNDPROC lpprevwndfunc, HWND hwnd, UINT Msg, WPARAM wparam, LPARAM lparam ); 如 :
窗口 LRESULT CALLBACK SCWndProc(HWND hwnd, UINT wmsg, WPARAM wparam, LPARAM lparam); WNDPROC lpfnoldproc = 0; // 指向原窗口过程 // 窗口子类化 窗口 hwndsc BOOL SubClassThisWnd (HWND hwndsc) { if (lpfnoldproc == 0) { // 获取原窗口过程 lpfnoldproc = (WNDPROC)GetWindowLong (hwndsc, GWL_WNDPROC); // 指向新窗口过程 return SetWindowLong (hwndsc, GWL_WNDPROC, (DWORD)SCWndProc); } return FALSE; }
窗口 // 新窗口过程 LRESULT CALLBACK SCWndProc(HWND hwnd, UINT wmsg, WPARAM wparam, LPARAM lparam) { switch (wmsg) { case WM_LBUTTONDOWN: MessageBeep(0); break; } return CallWindowProc (lpfnoldproc, hwnd, wmsg, wparam, lparam); } 要去除窗口的子类化, 只要调用 SetWindowLong, 把 WndProc 指针设置回最初的窗口过程即可 SetWindowLong (hwndsc, GWL_WNDPROC, lpfnoldproc);
控件 窗口类控件 简单的说, 控件只不过是预先定义好的窗口类 每个类有一个 Windows 提供的特定的窗口过程, 给这些控件提供预定义的用户和编程接口 控件只是又一个窗口, 所以可用 CreateWindows 或 CreateWindowEx 来创建 控件是通过事件来通知父窗口的, 而事件中包含 WM_COMMAND 消息, 并且控件 ID 和句柄都编码在消息的参数中 WM_COMMAND 消息 wparam 的高字位含有通知码, 用来说明发送该消息的原因 wparam 的低字位含有发送该消息控件的 ID lparam 包含了控件窗口的句柄 通常, 通过控件 ID 来追踪 WM_COMMAND 消息来源比通过控件的窗口句柄来追踪要更容易一些, 不过这两个信息都可以从该消息中获得
控件 一个典型的 WM_COMMAND 消息处理程序中的头几行代码如下 : case WM_COMMAND: WORD iditem, wnotifycode; HWND hwndctl; // Parse the parameters. iditem = (WORD) LOWORD (wparam); wnotifycode = (WORD) HIWORD(wParam); hwndctl = (HWND) lparam;
窗口 控件 ID 转换句柄函数 HWND GetDlgItem(HWND hdlg, int niddlgitem); 两个参数分别是控件的父窗口句柄和控件的 ID 给控件发送消息函数 LONG SendDlgItemMessage (HWND hparent, int nidchild, UINT Msg, WPARAM wparam, LPARAM lparam); 实际上, 下面的这段代码从功能上讲和 SendDlgItemMessage 一样 LONG SendMessage (GetDlgItem (hparent, nidchild), Msg, wparam, lparam);
控件 六个预定义的窗口控件类 : BUTTON 各种按钮 EDIT 一种用于输入和显示文本的窗口 LISTBOX 一种包含字符串列表的窗口 COMBOBOX 编辑框和列表框的组合 STATIC 显示用户不能编辑的文本或图片的窗口 SCROLLBAR 未和具体窗口进行绑定滚动条
控件 按钮控件 BUTTON 按钮控件有许多风格, 包括 下压按钮 复选框 单选框 分组框
控件 下压按钮 (BUTTON) 下压按钮通常用于激发某种行为 当用户用手写笔按一个下压按钮, 按钮会发送 WM_COMMAND 消息, 其中 wparam 参数的高字位包含 BN_CLICKED( 用于按钮被单击的通知 ) 通知码 风格 :BS_DEFPUSHBUTTON BS_PUSHBUTTON 如, 下句在 WM_PAINT 消息中生成一个按钮 (btnexam) ( 设有 : #define IDC_PUSHBTN 100 ) HWND hwndchild = CreateWindow (TEXT ( BUTTON ), TEXT("Sip"), BS_PUSHBUTTON WS_VISIBLE WS_CHILD, 10, 120, 80, 20, hwnd, (HMENU)IDC_PUSHBTN, hinst, NULL); 在 WM_COMMAND 消息中对 BN_CLICKED 通知码进行处理, 显示或关闭软键盘
控件 WORD iditem, wnotifycode; HWND hwndctl; SIPINFO sf; iditem = (WORD) LOWORD (wparam); wnotifycode = (WORD) HIWORD(wParam); hwndctl = (HWND) lparam; if (iditem == IDC_PUSHBTN) { if (wnotifycode == BN_CLICKED) if (!gsipshow) { SipShowIM(SIPF_ON); gsipshow=true;} else { SipShowIM(SIPF_OFF); gsipshow=false;} }
控件 复选框 (BUTTON) 复选框包括一个正方形的框和一个标签, 用来让用户指定选择 风格 :BS_CHECKBOX BS_3STATE BS_AUTOCHECKBOX 和 BS_AUTO3STATE 当单击复选框时, 会发送 BN_CLICKED 通知 如, 下句生成一个复选框 hwndchild = CreateWindow (TEXT ("BUTTON"), TEXT( CheckBox ), BS_AUTOCHECKBOX WS_VISIBLE WS_CHILD, 0, 0, 80, 20, hwnd, NULL, hinst, NULL);
控件 复选框 (BUTTON) ( 续 ) 除非复选框具有自动风格, 否则需应用程序负责手工改变按钮的状态 通过给按钮发送 BM_SETCHECK 消息来设置按钮的状态, 其中, 把参数 wparam 设置为 0 来取消按钮选择,1 则是选择按钮 对于三态复选框,2 表示按钮失效 通过 BM_GETCHECK 消息, 应用程序可以判断当前按钮状态 如 : 下列代码改变复选按钮选项. // Get the current state, complement, and set. i = SendDlgItemMessage (hwnd, IDC_CHKBOX, BM_GETCHECK, 0, 0); if (i == 0) SendDlgItemMessage (hwnd, IDC_CHKBOX, BM_SETCHECK, 1, 0); else SendDlgItemMessage (hwnd, IDC_CHKBOX, BM_SETCHECK, 0, 0);
控件 单选框 (BUTTON) 单选框允许用户从多个选项里进行选择 风格 : 有 BS_RADIOBUTTON 和 BS_AUTORADIONBUTTON 分组框 (BUTTON) 分组框包围着被分成一组的控件集 分组框只是用于分组, 除了其上的标题文字外, 没有其它编程的接口 风格 : BS_GROUPBOX 定制按钮外观 通过使用许多附加风格, 可以进一步定制按钮的外观 风格 :BS_RIGHT,BS_LEFT,BS_BOTTOM 和 BS_TOP 允许指定按钮文本的位置 风格 BS_MULTILINE 允许在按钮上指定多行文本 自绘制按钮
控件 编辑框 EDIT 编辑框是一种允许用户输入和编辑文本的窗口 风格 :ES_LEFT,ES_PASSWORD,ES_READONLY, WS_BORDER, ES_LOWERCASE 和 ES_UPPERCASE,ES_MULTILINE 等 相关消息 :WM_SETTEXT,WM_GETTEXT,EM_SETSEL 等 如, 下句生成一个编辑框 hwndchild = CreateWindow (TEXT("edit"),TEXT ("Edit"), WS_VISIBLE WS_CHILD ES_LEFT, 10, 10, 220, 100,hWnd, (HMENU)IDC_EDIT, hinst, NULL); 往编辑框增加内容 : SendDlgItemMessage (hwnd, IDC_EDIT, WM_SETTEXT, 0, (LPARAM)(LPCTSTR)szOut);
控件 列表框控件 LISTBOX 列表框控件显示一个文本项列表, 用户可以从中选择一个或多个项 风格 :LBS_COMBOBOX LBS_MULTICOLUMN LBS_MULTIPLESEL LBS_SORT LBS_USETABSTOPS 等 相关消息 :LB_ADDSTRING LB_INSERTSTRING LB_INSERTSTRING LB_FINDSTRING LB_GETCURSEL LB_GETSELCOUNT 和 LB_GETSELITEMS 等 如, 下句生成一个列表框 hwndchild = CreateWindowEx (WS_EX_CLIENTEDGE, TEXT ("listbox"),text (""), WS_VISIBLE WS_CHILD WS_VSCROLL LBS_USETABSTOPS, 0, 0, 100, 100,hWnd, (HMENU)IDC_RPTLIST, hinst, NULL);
控件 列表框控件 LISTBOX ( 续 ) 下句往列表框增加行 SendDlgItemMessage (hwnd, IDC_RPTLIST, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)szOut); 如 :(btnexam)
控件 组合框 COMBOBOX 组合框是一个单行编辑框控件和列表框的组合 风格 :CBS_DROPDOWN,CBS_DROPDOWNLIST,CBS_SORT, CBS_AUTOHSCROLL 等相关消息 :CB_ADDSTRING,CB_INSERTSTRING,CB_FINDSTRING, CB_SETEDITSELECT 和 CB_GETEDITSELECT 等 如 : 创建下拉列表框, 增加项. HWND hwndchild = CreateWindow (TEXT ("COMBOBOX"), TEXT(""), CBS_AUTOHSCROLL CBS_DROPDOWNLIST WS_VISIBLE WS_CHILD, 10, 20, 150, 60, hwnd, (HMENU)IDC_PUSHBTN, hinst, NULL); SendMessage (hwndchild, CB_ADDSTRING, 0, (LPARAM)L"1111"); SendMessage (hwndchild, CB_ADDSTRING, 0, (LPARAM)L"2222"); SendMessage (hwndchild, CB_SHOWDROPDOWN, true, 0); // 显示下拉
控件 静态控件 STATIC 静态控件是显示文本 图标或者位图的窗口, 不具有用户交互性 风格 :SS_LEFT,SS_CENTER,SS_RIGHT,SS_LEFTNOWORDWRAP, SS_BITMAP,SS_ICON 等相关消息 :WM_COMMAND 等 如 : HWND hwndchild = CreateWindow (TEXT ("STATIC"), TEXT("Test String"), SS_LEFT WS_VISIBLE WS_CHILD, 10, 20, 150, 20, hwnd, (HMENU)IDC_PUSHBTN1, hinst, NULL); if (!IsWindow (hwndchild)) { MessageBox(NULL,L Create Control Fail",L Info",MB_OK); DestroyWindow (hwnd); return 0; }
控件 滚动条控件 ( SCROLLBAR ) 通常滚动条是绑定在窗口的侧边, 用来控制窗口里数据的显示的 风格 :SBS_HORZ,SBS_VERT 相关消息 :WM_VSCROLL WM_HSCROLL 对这两个消息来说,wParam 和 lparam 参数是一样的 wparam 的低字位包含的代码指出为什么会发送该消息 下图显示了水平和垂直滚动条以及如何在滚动条不同位置点击来产生不同的消息 wparam 的高字位包含滑块的位置
控件
控件 滚动条参数设置函数 int SetScrollInfo(HWND hwnd, int fnbar, LPSCROLLINFO lpsi, BOOL fredraw); 第一个参数可以是包含滚动条的窗口的句柄, 也可以是滚动条自身的窗口句柄 第二个参数 fnbar 是一个标志位, 用于判断窗口句柄的用法 SB_HORZ: 用于窗口中标准水平滚动条 ; SB_VERT: 用于窗口中标准垂直滚动条 ; SB_CTL: 用于独立的滚动条控件 除非滚动条是控件, 否则窗口句柄是包含滚动条的窗口的句柄 在句柄是滚动条控件自身的句柄时, 使用 SB_CTL 第三个参数 lpsi 见下页 最后一个参数 freddraw, 一个布尔值, 指出是否在调用完成后重新绘制滚动条
第三个参数是指向 SCROLLINFO 结构的指针, 该结构定义如下 : typedef struct tagscrollinfo { UINT cbsize; UINT fmask; int nmin; int nmax; UINT npage; int npos; int ntrackpos; } SCROLLINFO 该结构允许您完整的指定滚动条参数 cbsize: 必须设置成 SCROLLINFO 结构的大小 fmask: 标志位, 指出结构中其它域包含什么样的有效数据 nmin 和 nmax: 包含滚动条的最小和最大滚动值 如果 fmask 参数包含 SIF_RANGE 标志,Windows 就会在这两个域中查找这些值 同样地, 如果 fmask 包含 SIF_POS 标志,nPos 在预定义的范围内设置滚动条位置 npage: 允许程序定义屏幕当前可视区域相对于整个滚动区域的大小 只有当 fmask 中包含 SIF_PAGE 标志的时候这个域才有用 ntrackpos:setscrollinfo 不使用并忽略掉它 fmask 最后一个标志是 SIF_DISABLENOSCROLL, 可以让滚动条失效但可视
控件 如 : HWND hwndchild = CreateWindow (TEXT ("SCROLLBAR"), TEXT("Test String"), SBS_HORZ WS_VISIBLE WS_CHILD, 10, 20, 150, 20, hwnd, (HMENU)IDC_PUSHBTN1, hinst, NULL); SCROLLINFO scri; scri.fmask = SIF_ALL; scri.nmax = 100; scri.nmin =0; scri.npos=40; // 滚动条当前位置 scri.npage=10; // 滚动条宽度 SetScrollInfo(hwndChild,SB_CTL,&scri,true);
控件 CtlView 程序示例
控件 CtlView 程序示例
菜单 创建菜单函数 HMENU CreateMenu(void) 创建一个空菜单, 函数返回此空菜单的句柄 HMENU CreatePopMenu(void) 创建一个空的 pop-up 菜单, 函数返回此空菜单的句柄 BOOL AppendMenu (HMENU hmenu, UINT fuflags, UINT idnewitem, LPCTSTR lpsznewitem) 在菜单末尾添加一个菜单项 fuflages: 用来指示菜单项的初始情形 如, 失效 (MF_GRAYED) 或选择 (MF_CHECKED) 几乎所有的调用都会指定 MF_STRING, 表示 lpsznewitem 参数是包含菜单项文本的字符串 idnewitem 表示用户选择的菜单项 ID 或者需要改变的菜单项的状态 BOOL InsertMenu(HMENU hmenu, UINT uposition, UINT uflags, UINT uidnewitem, LPCTSTR lpnewitem); 在菜单中插入一个菜单项
菜单 菜单可采用嵌套来达到级联效果 要增加一个级联菜单或者子菜单, 可 : 1) 用 HMENU CreatePopMenu(void) 来创建想绑定的菜单 ; 2) 再用 InsertMenu 或者 AppendMenu 来构造该菜单, 3) 通过把 fuflags 标志位设置为 MF_POPUP, 调用 InsertMenu 或者 AppendMenu 将上步子菜单插入或者附加到主菜单上 在这种情况下,uIDNewItem 包含的是子菜单的句柄, 而 lpnewitem 包含的是显示在菜单项里的字符串 如
菜单 hmainmenu = CreateMenu (); hmenu = CreatePopupMenu (); AppendMenu (hmenu, MF_STRING MF_ENABLED, 100, TEXT ("&New")); AppendMenu (hmenu, MF_STRING MF_ENABLED, 101, TEXT ("&Open")); AppendMenu (hmenu, MF_STRING MF_ENABLED, 102, TEXT ("&Save")); AppendMenu (hmenu, MF_STRING MF_ENABLED, 103, TEXT ("E&xit")); AppendMenu (hmainmenu, MF_STRING MF_ENABLED MF_POPUP, (UINT)hMenu, TEXT ("&File"));
菜单 hmenu = CreatePopupMenu (); AppendMenu (hmenu, MF_STRING MF_ENABLED, 110, TEXT ("C&ut")); AppendMenu (hmenu, MF_STRING MF_ENABLED, 111, TEXT ("&Copy")); AppendMenu (hmenu, MF_STRING MF_ENABLED, 112, TEXT ("&Paste")); AppendMenu (hmainmenu, MF_STRING MF_ENABLED MF_POPUP, (UINT)hMenu, TEXT ("&Edit")); hmenu = CreatePopupMenu (); AppendMenu (hmenu, MF_STRING MF_ENABLED, 120, TEXT ("&About")); AppendMenu (hmainmenu, MF_STRING MF_ENABLED MF_POPUP, (UINT)hMenu, TEXT ("&Help"));
菜单 设置菜单 BOOL EnableMenuItem (HMENU hmenu, UINT uidenableitem, UINT uenable); 使菜单项有效 / 失效 DWORD CheckMenuItem (HMENU hmenu, UINT uidcheckitem, UINT ucheck); 选择菜单项 / 去除选择 显示菜单 BOOL TrackPopupMenu(HMENU hmenu, UINT uflags, int x, int y, int nreserved, HWND hwnd, const RECT* prcrect ); 该函数在指定位置显示快捷菜单, 并跟踪菜单项的选择 快捷菜单可出现在屏幕上的任何位置
菜单 hmenu: 被显示的快捷菜单的句柄 uflags: 一种指定功能选项的位标志 TPM_CENTERALIGN: 按 x 指定的坐标水平居中放置快捷菜单 TPM_LEFTALIGN: 使快捷菜单的左边界与由 X 指定的坐标对齐 TPM_RIGHTALIGN: 使菜单的右边界与由 X 指定的坐标对齐 TPM_BOTTOMALIGN: 使菜单的下边界与由 y 指定的坐标对齐 TPM_TOPALIGN: 使快捷菜单的上边界与由 y 指定的坐标对齐 TPM_VCENTERALIGN; 将按 y 指定的坐标垂直居中放置快捷菜单 TPM_NONOTIFY: 当用户单击菜单项时函数不发送通知消息 TPM_RETURNCMD: 将用户所选菜单项的标识符返回到返回值里 x y: 屏幕坐标下, 快捷菜单的水平 垂直位置 Hwnd: 是接收所有与菜单相关消息的窗口句柄 prcrect: 未用
菜单 如, 显示一个快捷菜单 : TrackPopupMenu (hmenu,tpm_leftalign TPM_RETURNCMD, 50,150,0, hwnd, 0); 处理菜单命令 当用户选择了一个菜单项,Windows 会向拥有该菜单的窗口发送 WM_COMMAND 消息 :wparam 的低字位包含被选择的菜单项的 ID, 高字位包含通知码, 对 菜单选择 这个动作来说, 该值总是 0 lparam 是 0
窗口 控件和菜单 资源 资源是应用程序或 DLL 的一个只读数据段, 在模块被编译后, 资源被链接到模块中 资源为开发者提供了一个与编译器无关的位置, 用来存储常量数据, 例如对话框 字符串 位图 图标以及菜单 因为资源并不编译在程序里, 所以改变它们并不用重新编译程序
窗口 控件和菜单 资源相关函数 LoadMenu 从与应用程序相关联的可执行文件 (.EXE) 中加载菜单资源 HMENU LoadMenu( HINSTANCE hinstance, LPCTSTR lpmenuname ); hlnstance: 含有被加载菜单资源的事例模块的句柄 LpMenuName: 指向含有菜单资源名的字符串指针
窗口 控件和菜单 资源相关函数 ( 续 ) LoadImage 该函数装载目标, 光标, 或位图 HANDLE LoadImage( HINSTANCE hinst, LPCTSTR lpszname, UINT utype, int cxdesired, int cydesired, UINT fuload ); hinst: 处理包含被装载图像模块的实例 lpszname: 一个指向保留在 hinst 模块中装载的图像资源名称 utype: 指定被装载图像类型 此参数可为下值, 其含义如下 : IMAGE_BITMAP: 装载位图 ; IMAGE_CURSOR: 装载光标 ; IMAGE_ICON: 装载图标 cxdesired: 指定图标或光标的宽度, 以像素为单位 cydesired: 指定图标或光标的高度, 以像素为单位 fuload:wince 为 0
窗口 控件和菜单 资源相关函数 (LoadImage 续 ) 如 : 下面的代码片段为窗口分派一个小图标 ( 在任务栏上 ) HANDLE hicon = (HICON) SendMessage (hwnd, WM_GETICON, FALSE, 0); if (hicon == 0) { hicon = LoadImage (hinst, MAKEINTRESOURCE (IDI_szTestHello), IMAGE_ICON, 16, 16, 0); SendMessage (hwnd, WM_SETICON, FALSE, (LPARAM)hIcon); } 第一个 SendMessage 用来获取窗口当前分配的图标 wparam 中的 FALSE 值指出要查询窗口的小图标 如果返回 0, 表示没有图标分配过 LoadImage 函数可以用文本字符串或者 ID 值来标记要装载的资源 MAKEINTRESOURCE 宏用来为函数生成一个 ID 值 在 WinCE 中, 被装载的图标必须是 16*16 的图标 在 WinCE 下, LoadImage 只限于从资源中装载图标和位图 Windows CE 另外提供了 SHLoadDIBitmap 函数用于从文件中装载位图
窗口 控件和菜单 资源相关函数 ( 续 ) LoadAccelerators 调入加速键表 该函数调入指定的加速键表 HACCEL LoadAccelerators( HINSTANCE hinstance, LPCTSTR lptablename ); hlnstance: 包含加速键表模块的实例句柄 IpTableName: 指向加速键表名字的指针 要使用加速键, 应用程序应装载加速键表 对从消息队列中取出的每个消息, 应用程序还要检查是否有加速键 下面是一个修改后的处理键盘加速键的主消息循环
窗口 控件和菜单 haccel = LoadAccelerators (hinst, MAKEINTRESOURCE (ID_ACCEL)); while (GetMessage (&msg, NULL, 0, 0)) // Application message loop { if (!TranslateAccelerator (hwndmain, haccel, &msg)) // 转换加速键 { TranslateMessage (&msg); DispatchMessage (&msg); } } LoadAccelerators 函数 : 装载加速键表 TranslateAccelerator: 如果该函数转换了消息, 返回值是 TRUE, 这将跳过标准的 TranslateMessage 和 DispatchMessage 循环体 如果没有转换, 循环体就正常执行
窗口 控件和菜单 LoadString: 从资源中装载字符串 int LoadString(HINSTANCE hinstance, UINT uid, LPTSTR lpbuffer, int nbuffermax ); uid 是字符串资源的 ID; lpbuffer 指向接收字符串的缓冲区 ; nbuffermax 是缓冲区的大小 在 Windows CE 里, 为了节省内存,LoadString 有一个新特性 如果 lpbuffer 是 NULL,LoadString 返回一个指向字符串的只读的指针作为返回值
窗口 控件和菜单 DOIView 程序示例 演示了资源 键盘加速键和弹出式菜单的用法