原文: http://zetcode.com/gui/winapi/controlsII/

我们继续使用 Windows 控件。 我们将展示如何使用跟踪栏,工具提示和月历控件。

跟踪栏

跟踪栏是一个包含滑块和可选刻度线的窗口。 我们使用鼠标或键盘移动滑块。 跟踪栏用于从一系列连续值中选择离散值。 在其他平台上,此控件称为滑块。

trackbar.c

  1. #include <windows.h>
  2. #include <commctrl.h>
  3. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  4. void CreateControls(HWND hwnd);
  5. void UpdateLabel(void);
  6. HWND hTrack;
  7. HWND hlbl;
  8. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  9. PWSTR lpCmdLine, int nCmdShow) {
  10. HWND hwnd;
  11. MSG msg ;
  12. WNDCLASSW wc = {0};
  13. wc.lpszClassName = L"Trackbar";
  14. wc.hInstance = hInstance;
  15. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  16. wc.lpfnWndProc = WndProc;
  17. wc.hCursor = LoadCursor(0,IDC_ARROW);
  18. RegisterClassW(&wc);
  19. hwnd = CreateWindowW(wc.lpszClassName, L"Trackbar",
  20. WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 350, 180, 0, 0, hInstance, 0);
  21. while (GetMessage(&msg, NULL, 0, 0)) {
  22. TranslateMessage(&msg);
  23. DispatchMessage(&msg);
  24. }
  25. return (int) msg.wParam;
  26. }
  27. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  28. WPARAM wParam, LPARAM lParam) {
  29. switch(msg) {
  30. case WM_CREATE:
  31. CreateControls(hwnd);
  32. break;
  33. case WM_HSCROLL:
  34. UpdateLabel();
  35. break;
  36. case WM_DESTROY:
  37. PostQuitMessage(0);
  38. break;
  39. }
  40. return DefWindowProcW(hwnd, msg, wParam, lParam);
  41. }
  42. void CreateControls(HWND hwnd) {
  43. HWND hLeftLabel = CreateWindowW(L"Static", L"0",
  44. WS_CHILD | WS_VISIBLE, 0, 0, 10, 30, hwnd, (HMENU)1, NULL, NULL);
  45. HWND hRightLabel = CreateWindowW(L"Static", L"100",
  46. WS_CHILD | WS_VISIBLE, 0, 0, 30, 30, hwnd, (HMENU)2, NULL, NULL);
  47. hlbl = CreateWindowW(L"Static", L"0", WS_CHILD | WS_VISIBLE,
  48. 270, 20, 30, 30, hwnd, (HMENU)3, NULL, NULL);
  49. INITCOMMONCONTROLSEX icex;
  50. icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  51. icex.dwICC = ICC_LISTVIEW_CLASSES;
  52. InitCommonControlsEx(&icex);
  53. hTrack = CreateWindowW(TRACKBAR_CLASSW, L"Trackbar Control",
  54. WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS,
  55. 20, 20, 170, 30, hwnd, (HMENU) 3, NULL, NULL);
  56. SendMessageW(hTrack, TBM_SETRANGE, TRUE, MAKELONG(0, 100));
  57. SendMessageW(hTrack, TBM_SETPAGESIZE, 0, 10);
  58. SendMessageW(hTrack, TBM_SETTICFREQ, 10, 0);
  59. SendMessageW(hTrack, TBM_SETPOS, FALSE, 0);
  60. SendMessageW(hTrack, TBM_SETBUDDY, TRUE, (LPARAM) hLeftLabel);
  61. SendMessageW(hTrack, TBM_SETBUDDY, FALSE, (LPARAM) hRightLabel);
  62. }
  63. void UpdateLabel(void) {
  64. LRESULT pos = SendMessageW(hTrack, TBM_GETPOS, 0, 0);
  65. wchar_t buf[4];
  66. wsprintfW(buf, L"%ld", pos);
  67. SetWindowTextW(hlbl, buf);
  68. }

在我们的示例中,我们显示带有三个静态文本控件的跟踪栏控件。 其中两个连接在跟踪栏的左侧和右侧。 他们被称为伙伴。 通过拖动滑块,我们可以更改第三个静态控件的文本。

  1. HWND hLeftLabel = CreateWindowW(L"Static", L"0",
  2. WS_CHILD | WS_VISIBLE, 0, 0, 10, 30, hwnd, (HMENU)1, NULL, NULL);
  3. HWND hRightLabel = CreateWindowW(L"Static", L"100",
  4. WS_CHILD | WS_VISIBLE, 0, 0, 30, 30, hwnd, (HMENU)2, NULL, NULL);
  5. hlbl = CreateWindowW(L"Static", L"0", WS_CHILD | WS_VISIBLE,
  6. 270, 20, 30, 30, hwnd, (HMENU)3, NULL, NULL);

创建了三个静态控件。 两个控件将显示跟踪栏控件的最小值和最大值。 最后一个将显示当前选定的值。

  1. INITCOMMONCONTROLSEX icex;
  2. icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  3. icex.dwICC = ICC_LISTVIEW_CLASSES;
  4. InitCommonControlsEx(&icex);

如果要使用公共控件之一,则需要加载公共控件 DLL(comctl32.dll)并从 DLL 中注册特定的公共控件类。 在创建通用控件之前,InitCommonControlsEx()必须调用此函数。

  1. hTrack = CreateWindowW(TRACKBAR_CLASSW, L"Trackbar Control",
  2. WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS,
  3. 20, 20, 170, 30, hwnd, (HMENU) 3, NULL, NULL);

TRACKBAR_CLASSW用于创建轨迹栏控件。 TBS_AUTOTICKS样式会为其值范围内的每个增量创建一个刻度线。

  1. SendMessageW(hTrack, TBM_SETRANGE, TRUE, MAKELONG(0, 100));
  2. SendMessageW(hTrack, TBM_SETPAGESIZE, 0, 10);
  3. SendMessageW(hTrack, TBM_SETTICFREQ, 10, 0);
  4. SendMessageW(hTrack, TBM_SETPOS, FALSE, 0);

跟踪栏控件尚未完成。 我们向控件发送四个消息。 我们发送TBM_SETRANGE设置轨迹栏范围。 要设置页面大小,我们发送TBM_SETPAGESIZE消息。 要设置刻度频率,我们发送TBM_SETTICFREQ消息。 要设置当前滑块位置,我们发送TBM_SETPOS

  1. SendMessageW(hTrack, TBM_SETBUDDY, TRUE, (LPARAM) hLeftLabel);
  2. SendMessageW(hTrack, TBM_SETBUDDY, FALSE, (LPARAM) hRightLabel);

我们通过发送TBM_SETBUDDY消息来设置轨迹栏好友。 第三个参数将决定伙伴是位于控件的左侧(TRUE)还是右侧(FALSE)。

  1. case WM_HSCROLL:
  2. UpdateLabel();
  3. break;

当我们移动轨迹栏滑块时,窗口过程将收到WM_HSCROLL消息。 (如果是水平跟踪栏。)

  1. void UpdateLabel(void) {
  2. LRESULT pos = SendMessageW(hTrack, TBM_GETPOS, 0, 0);
  3. wchar_t buf[4];
  4. wsprintfW(buf, L"%ld", pos);
  5. SetWindowTextW(hlbl, buf);
  6. }

UpdateLabel()函数中,我们通过发送TMB_GETPOS消息来获得当前滑块的位置。 使用wsprintfW()函数将接收到的值转换为文本。 最后,通过SetWindowTextW()函数设置静态控件的文本。

Windows API 控件 II - 图1

图:跟踪栏

工具提示

工具提示是常见的图形用户元素。 工具提示大部分时间都是隐藏的。 这是一个小框,当鼠标指针经过时会出现在 GUI 对象附近。 它显示一条简短的消息,说明该对象。 工具提示是应用帮助系统的一部分。

tooltip.c

  1. #include <windows.h>
  2. #include <commctrl.h>
  3. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  4. void CreateMyTooltip(HWND);
  5. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  6. LPSTR lpCmdLine, int nCmdShow) {
  7. MSG msg;
  8. WNDCLASS wc = {0};
  9. wc.lpszClassName = "Tooltip";
  10. wc.hInstance = hInstance;
  11. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  12. wc.lpfnWndProc = WndProc;
  13. wc.hCursor = LoadCursor(0, IDC_ARROW);
  14. RegisterClass(&wc);
  15. CreateWindow(wc.lpszClassName, "Tooltip",
  16. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  17. 100, 100, 200, 150, 0, 0, hInstance, 0);
  18. while (GetMessage(&msg, NULL, 0, 0)) {
  19. TranslateMessage(&msg);
  20. DispatchMessage(&msg);
  21. }
  22. return (int) msg.wParam;
  23. }
  24. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  25. switch(msg) {
  26. case WM_CREATE:
  27. CreateMyTooltip(hwnd);
  28. break;
  29. case WM_DESTROY:
  30. PostQuitMessage(0);
  31. break;
  32. }
  33. return DefWindowProc(hwnd, msg, wParam, lParam);
  34. }
  35. void CreateMyTooltip(HWND hwnd) {
  36. INITCOMMONCONTROLSEX iccex;
  37. HWND hwndTT;
  38. TOOLINFO ti;
  39. char tooltip[30] = "A main window";
  40. RECT rect;
  41. iccex.dwICC = ICC_WIN95_CLASSES;
  42. iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  43. InitCommonControlsEx(&iccex);
  44. hwndTT = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
  45. WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
  46. 0, 0, 0, 0, hwnd, NULL, NULL, NULL );
  47. SetWindowPos(hwndTT, HWND_TOPMOST, 0, 0, 0, 0,
  48. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  49. GetClientRect(hwnd, &rect);
  50. ti.cbSize = sizeof(TOOLINFO);
  51. ti.uFlags = TTF_SUBCLASS;
  52. ti.hwnd = hwnd;
  53. ti.hinst = NULL;
  54. ti.uId = 0;
  55. ti.lpszText = tooltip;
  56. ti.rect.left = rect.left;
  57. ti.rect.top = rect.top;
  58. ti.rect.right = rect.right;
  59. ti.rect.bottom = rect.bottom;
  60. SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
  61. }

在我们的示例中,我们为主窗口设置了一个工具提示。

  1. INITCOMMONCONTROLSEX iccex;
  2. ...
  3. iccex.dwICC = ICC_WIN95_CLASSES;
  4. iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  5. InitCommonControlsEx(&iccex);

工具提示是通用控件的一部分,因此,我们必须初始化通用控件。

工具提示的创建包含几个步骤。 我们必须创建一个工具提示窗口。 然后我们将其设置为最顶层的窗口,这样它就不会被另一个窗口覆盖。 我们创建一个工具提示文本和TOOLTIPINFO结构。 该结构必须填充重要信息。 窗口句柄,工具提示文本和矩形将覆盖我们的工具提示。 在我们的示例中,我们的工具提示将覆盖窗口的整个客户区域。

  1. SendMessage(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);

在发送TTM_ADDTOOL消息后,工具提示确实添加到了窗口中。

Windows API 控件 II - 图2

图:工具提示 control

Updown 控件

Updown 控件(也称为旋转控件)将一对显示为箭头的按钮与一个好友编辑控件结合在一起。 单击箭头可增加或减少编辑控件中的值。 Updown 控件是使用UPDOWN_CLASSW窗口类创建的。

updown.c

  1. #include <windows.h>
  2. #include <commctrl.h>
  3. #include <strsafe.h>
  4. #define ID_UPDOWN 1
  5. #define ID_EDIT 2
  6. #define ID_STATIC 3
  7. #define UD_MAX_POS 30
  8. #define UD_MIN_POS 0
  9. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  10. void CreateControls(HWND);
  11. HWND hUpDown, hEdit, hStatic;
  12. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  13. PWSTR lpCmdLine, int nCmdShow) {
  14. MSG msg;
  15. WNDCLASSW wc = {0};
  16. wc.style = CS_HREDRAW | CS_VREDRAW;
  17. wc.lpszClassName = L"Updown control";
  18. wc.hInstance = hInstance;
  19. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  20. wc.lpfnWndProc = WndProc;
  21. wc.hCursor = LoadCursor(0, IDC_ARROW);
  22. RegisterClassW(&wc);
  23. CreateWindowW(wc.lpszClassName, L"Updown control",
  24. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  25. 100, 100, 280, 200, NULL, NULL, hInstance, NULL);
  26. while (GetMessage(&msg, NULL, 0, 0)) {
  27. DispatchMessage(&msg);
  28. }
  29. return (int) msg.wParam;
  30. }
  31. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  32. WPARAM wParam, LPARAM lParam) {
  33. LPNMUPDOWN lpnmud;
  34. UINT code;
  35. switch(msg) {
  36. case WM_CREATE:
  37. CreateControls(hwnd);
  38. break;
  39. case WM_NOTIFY:
  40. code = ((LPNMHDR) lParam)->code;
  41. if (code == UDN_DELTAPOS) {
  42. lpnmud = (NMUPDOWN *) lParam;
  43. int value = lpnmud->iPos + lpnmud->iDelta;
  44. if (value < UD_MIN_POS) {
  45. value = UD_MIN_POS;
  46. }
  47. if (value > UD_MAX_POS) {
  48. value = UD_MAX_POS;
  49. }
  50. const int asize = 4;
  51. wchar_t buf[asize];
  52. size_t cbDest = asize * sizeof(wchar_t);
  53. StringCbPrintfW(buf, cbDest, L"%d", value);
  54. SetWindowTextW(hStatic, buf);
  55. }
  56. break;
  57. case WM_DESTROY:
  58. PostQuitMessage(0);
  59. break;
  60. }
  61. return DefWindowProcW(hwnd, msg, wParam, lParam);
  62. }
  63. void CreateControls(HWND hwnd) {
  64. INITCOMMONCONTROLSEX icex;
  65. icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
  66. icex.dwICC = ICC_UPDOWN_CLASS;
  67. InitCommonControlsEx(&icex);
  68. hUpDown = CreateWindowW(UPDOWN_CLASSW, NULL, WS_CHILD | WS_VISIBLE
  69. | UDS_SETBUDDYINT | UDS_ALIGNRIGHT,
  70. 0, 0, 0, 0, hwnd, (HMENU) ID_UPDOWN, NULL, NULL);
  71. hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, NULL, WS_CHILD
  72. | WS_VISIBLE | ES_RIGHT, 15, 15, 70, 25, hwnd,
  73. (HMENU) ID_EDIT, NULL, NULL);
  74. hStatic = CreateWindowW(WC_STATICW, L"0", WS_CHILD | WS_VISIBLE
  75. | SS_LEFT, 15, 60, 300, 230, hwnd, (HMENU) ID_STATIC, NULL, NULL);
  76. SendMessageW(hUpDown, UDM_SETBUDDY, (WPARAM) hEdit, 0);
  77. SendMessageW(hUpDown, UDM_SETRANGE, 0, MAKELPARAM(UD_MAX_POS, UD_MIN_POS));
  78. SendMessageW(hUpDown, UDM_SETPOS32, 0, 0);
  79. }

在代码示例中,我们有一个 UpDown 控件和一个静态文本控件。 当前选定的 UpDown 值显示在静态文本控件中。

  1. #define UD_MAX_POS 30
  2. #define UD_MIN_POS 0

这两个常数用于 UpDown 控件的最大值和最小值。

  1. hUpDown = CreateWindowW(UPDOWN_CLASSW, NULL, WS_CHILD | WS_VISIBLE
  2. | UDS_SETBUDDYINT | UDS_ALIGNRIGHT,
  3. 0, 0, 0, 0, hwnd, (HMENU) ID_UPDOWN, g_hInst, NULL);

为了创建 UpDown 控件,我们将UPDOWN_CLASSW传递给CreateWindowW()函数。 UDS_SETBUDDYINT标志使 UpDown 控件在其位置更改时向其好友发送消息(WM_SETTEXT)。 UDS_ALIGNRIGHT标志将 UpDown 控件放置在其伙伴窗口右边缘的旁边。

  1. SendMessageW(hUpDown, UDM_SETBUDDY, (WPARAM) hEdit, 0);

UDM_SETBUDDY消息将编辑控件设置为 UpDown 控件的好友窗口。

  1. SendMessageW(hUpDown, UDM_SETRANGE, 0, MAKELPARAM(UD_MAX_POS, UD_MIN_POS));

UDM_SETRANGE消息设置 UpDown 控件的最小和最大位置。

  1. SendMessageW(hUpDown, UDM_SETPOS32, 0, 0);

通过UDM_SETPOS32消息,我们设置 UpDown 控件的初始位置。

  1. code = ((LPNMHDR) lParam)->code;
  2. if (code == UDN_DELTAPOS) {
  3. ...
  4. }

当控件的位置即将更改时(即在控件更新其值之前),操作系统会将UDN_DELTAPOS通知发送到 UpDown 控件的父窗口。

  1. lpnmud = (NMUPDOWN *) lParam;
  2. int value = lpnmud->iPos + lpnmud->iDelta;

NMUPDOWN结构包含有关 UpDown 修改的信息。 iPos值是 UpDown 控件的当前位置。 iDelta是 UpDown 控件位置的建议更改。 根据这两个值,我们计算出将出现在控件中的最终值。

  1. if (value < UD_MIN_POS) {
  2. value = UD_MIN_POS;
  3. }
  4. if (value > UD_MAX_POS) {
  5. value = UD_MAX_POS;
  6. }

此代码确保静态文本不会显示超出 UpDown 范围的值。

  1. int const asize = 4;
  2. wchar_t buf[asize];
  3. size_t cbDest = asize * sizeof(wchar_t);
  4. StringCbPrintfW(buf, cbDest, L"%d", value);

使用StringCbPrintfW()函数,我们构建了要在静态文本控件中显示的字符串。

  1. SetWindowTextW(hStatic, buf);

最后,使用SetWindowTextW()函数更新静态文本控件。

Windows API 控件 II - 图3

图:UpDown 控件

MonthCalendar控件

月历是一个复杂的控件,用于选择日期。 可以通过简单直观的方式选择日期。

monthcalendar.c

  1. #include <windows.h>
  2. #include <commctrl.h>
  3. #include <wchar.h>
  4. #include <strsafe.h>
  5. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  6. void CreateControls(HWND);
  7. void GetSelectedDate(HWND, HWND);
  8. HWND hStat;
  9. HWND hMonthCal;
  10. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  11. LPSTR lpCmdLine, int nCmdShow) {
  12. HWND hwnd;
  13. MSG msg;
  14. WNDCLASSW wc = {0};
  15. wc.lpszClassName = L"Month Calendar";
  16. wc.hInstance = hInstance ;
  17. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  18. wc.lpfnWndProc = WndProc ;
  19. wc.hCursor = LoadCursor(0, IDC_ARROW);
  20. RegisterClassW(&wc);
  21. hwnd = CreateWindowW(wc.lpszClassName, L"Month Calendar",
  22. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  23. 100, 100, 250, 300, 0, 0, hInstance, 0);
  24. while (GetMessage(&msg, NULL, 0, 0)) {
  25. DispatchMessage(&msg);
  26. }
  27. return (int) msg.wParam;
  28. }
  29. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  30. WPARAM wParam, LPARAM lParam) {
  31. LPNMHDR lpNmHdr;
  32. switch(msg) {
  33. case WM_CREATE:
  34. CreateControls(hwnd);
  35. break;
  36. case WM_NOTIFY:
  37. lpNmHdr = (LPNMHDR) lParam;
  38. if (lpNmHdr->code == MCN_SELECT) {
  39. GetSelectedDate(hMonthCal, hStat);
  40. }
  41. break;
  42. case WM_DESTROY:
  43. PostQuitMessage(0);
  44. break;
  45. }
  46. return DefWindowProcW(hwnd, msg, wParam, lParam);
  47. }
  48. void CreateControls(HWND hwnd) {
  49. hStat = CreateWindowW(WC_STATICW, L"",
  50. WS_CHILD | WS_VISIBLE, 80, 240, 80, 30,
  51. hwnd, (HMENU)1, NULL, NULL);
  52. INITCOMMONCONTROLSEX icex;
  53. icex.dwSize = sizeof(icex);
  54. icex.dwICC = ICC_DATE_CLASSES;
  55. InitCommonControlsEx(&icex);
  56. hMonthCal = CreateWindowW(MONTHCAL_CLASSW, L"",
  57. WS_BORDER | WS_CHILD | WS_VISIBLE | MCS_NOTODAYCIRCLE,
  58. 20, 20, 200, 200, hwnd, (HMENU)2, NULL, NULL);
  59. }
  60. void GetSelectedDate(HWND hMonthCal, HWND hStat) {
  61. SYSTEMTIME time;
  62. const int dsize = 20;
  63. wchar_t buf[dsize];
  64. ZeroMemory(&time, sizeof(SYSTEMTIME));
  65. SendMessage(hMonthCal, MCM_GETCURSEL, 0, (LPARAM) &time);
  66. size_t cbDest = dsize * sizeof(wchar_t);
  67. StringCbPrintfW(buf, cbDest, L"%d-%d-%d",
  68. time.wYear, time.wMonth, time.wDay);
  69. SetWindowTextW(hStat, buf);
  70. }

在我们的示例中,我们有两个控件:月历控件和静态文本。 从月历控件中选择的日期以静态文本显示。

  1. hMonthCal = CreateWindowW(MONTHCAL_CLASSW, L"",
  2. WS_BORDER | WS_CHILD | WS_VISIBLE | MCS_NOTODAYCIRCLE,
  3. 20, 20, 200, 200, hwnd, (HMENU)2, NULL, NULL);

在这里,我们创建一个月历控件。 创建月历控件的类名称为MONTHCAL_CLASSW。 如果使用MCS_NOTODAYCIRCLE窗口样式,则不会圈出今天的日期。

  1. INITCOMMONCONTROLSEX icex;
  2. icex.dwSize = sizeof(icex);
  3. icex.dwICC = ICC_DATE_CLASSES;
  4. InitCommonControlsEx(&icex);

要注册月历控件,我们为INITCOMMONCONTROLSEX结构的dwICC成员指定ICC_DATE_CLASSES标志。

  1. case WM_NOTIFY:
  2. lpNmHdr = (LPNMHDR) lParam;
  3. if (lpNmHdr->code == MCN_SELECT) {
  4. GetSelectedDate(hMonthCal, hStat);
  5. }
  6. break;

如果月份日历控件中发生事件,则会发送WM_NOTIFY消息。 lParam包含指向NMHDR结构的指针,该结构包含通知代码和其他信息。

  1. SendMessage(hMonthCal, MCM_GETCURSEL, 0, (LPARAM) &time);

为了用选定的日期填充结构,我们向日历控件发送了MCM_GETCURSEL消息。

  1. size_t cbDest = dsize * sizeof(wchar_t);
  2. StringCbPrintfW(buf, cbDest, L"%d-%d-%d",
  3. time.wYear, time.wMonth, time.wDay);
  4. SetWindowTextW(hStat, buf);

我们构建字符串并将日期设置为静态文本控件。

Windows API 控件 II - 图4

图:月历

在 Windows API 教程的这一部分中,我们继续介绍 Windows 控件-跟踪栏,工具提示,上下按钮和月份日历。