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

控件是 Windows 应用的基本构建块。 (控件在 UNIX 中称为小部件。)Windows API 教程的这一部分涵盖了静态控件,按钮,复选框和编辑框。

控件也是窗口。 它们是使用CreateWindowW()CreateWindowExW()函数创建的。 这些函数分别将窗口类名称作为其第一个和第二个参数。 控件具有其特定的预定义窗口类名称; 因此,在创建控件时,我们不会调用RegisterClassW()RegisterClassExW()

静态控件

静态控件显示文本和图形。 无法选择静态控件。 它还不能具有键盘焦点。

静态文字

在第一个示例中,我们创建一个静态文本控件。

static_text.c

  1. #include <windows.h>
  2. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  3. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  4. PWSTR lpCmdLine, int nCmdShow) {
  5. MSG msg;
  6. WNDCLASSW wc = {0};
  7. wc.lpszClassName = L"Static Control";
  8. wc.hInstance = hInstance;
  9. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  10. wc.lpfnWndProc = WndProc;
  11. wc.hCursor = LoadCursor(0, IDC_ARROW);
  12. RegisterClassW(&wc);
  13. CreateWindowW(wc.lpszClassName, L"Criminal",
  14. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  15. 100, 100, 330, 270, 0, 0, hInstance, 0);
  16. while (GetMessage(&msg, NULL, 0, 0)) {
  17. TranslateMessage(&msg);
  18. DispatchMessage(&msg);
  19. }
  20. return (int) msg.wParam;
  21. }
  22. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  23. WPARAM wParam, LPARAM lParam) {
  24. static wchar_t *lyrics = L"I know you told me I should stay away\n\
  25. I know you said he's just a dog astray\n\
  26. He is a bad boy with a tainted heart\n\
  27. And even I know this ain't smart\n\
  28. \n\
  29. But mama, I'm in love with a criminal\n\
  30. And this type of love isn't rational, it's physical\n\
  31. Mama, please don't cry, I will be alright\n\
  32. All reason aside, I just can't deny, love the guy\n\
  33. ";
  34. switch(msg) {
  35. case WM_CREATE:
  36. CreateWindowW(L"Static", lyrics,
  37. WS_CHILD | WS_VISIBLE | SS_LEFT,
  38. 20, 20, 300, 230,
  39. hwnd, (HMENU) 1, NULL, NULL);
  40. break;
  41. case WM_DESTROY:
  42. PostQuitMessage(0);
  43. break;
  44. }
  45. return DefWindowProcW(hwnd, msg, wParam, lParam);
  46. }

该示例在窗口上显示歌曲的歌词。

  1. CreateWindowW(L"Static", lyrics,
  2. WS_CHILD | WS_VISIBLE | SS_LEFT,
  3. 20, 20, 300, 230,
  4. hwnd, (HMENU) 1, NULL, NULL);
  5. break;

静态控件是使用L"Static"类创建的。 文本以SS_LEFT样式向左对齐。

Windows API 控件 I - 图1

Static text control

静态图像

第二个示例创建一个静态图像控件。

static_image.c

  1. #include <windows.h>
  2. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  3. void LoadMyImage(void);
  4. HBITMAP hBitmap;
  5. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  6. PWSTR lpCmdLine, int nCmdShow) {
  7. MSG msg;
  8. WNDCLASSW wc = {0};
  9. wc.lpszClassName = L"Static image";
  10. wc.hInstance = hInstance;
  11. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  12. wc.lpfnWndProc = WndProc;
  13. wc.hCursor = LoadCursor(0,IDC_ARROW);
  14. RegisterClassW(&wc);
  15. CreateWindowW(wc.lpszClassName, L"Static image",
  16. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  17. 100, 100, 330, 270, 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,
  25. WPARAM wParam, LPARAM lParam) {
  26. HWND hsti;
  27. switch(msg) {
  28. case WM_CREATE:
  29. LoadMyImage();
  30. hsti = CreateWindowW(L"Static", L"",
  31. WS_CHILD | WS_VISIBLE | SS_BITMAP,
  32. 5, 5, 300, 300, hwnd, (HMENU) 1, NULL, NULL);
  33. SendMessage(hsti, STM_SETIMAGE,
  34. (WPARAM) IMAGE_BITMAP, (LPARAM) hBitmap);
  35. break;
  36. case WM_DESTROY:
  37. DeleteObject(hBitmap);
  38. PostQuitMessage(0);
  39. break;
  40. }
  41. return DefWindowProcW(hwnd, msg, wParam, lParam);
  42. }
  43. void LoadMyImage(void) {
  44. hBitmap = LoadImageW(NULL, L"C:\\prog\\slovakia.bmp", IMAGE_BITMAP,
  45. 0, 0, LR_LOADFROMFILE);
  46. }

该示例在窗口上显示了 BMP 图像。

  1. hsti = CreateWindowW(L"Static", L"",
  2. WS_CHILD | WS_VISIBLE | SS_BITMAP,
  3. 5, 5, 300, 300, hwnd, (HMENU) 1, NULL, NULL);

SS_BITMAP常量使静态控件显示位图。

  1. SendMessage(hsti, STM_SETIMAGE,
  2. (WPARAM) IMAGE_BITMAP, (LPARAM) hBitmap);

发送STM_SETIMAGE消息以将新图像与静态控件关联。

  1. void LoadMyImage(void) {
  2. hBitmap = LoadImageW(NULL, L"C:\\prog\\slovakia.bmp", IMAGE_BITMAP,
  3. 0, 0, LR_LOADFROMFILE);
  4. }

LoadImageW()函数从文件系统加载位图。 如果函数成功,则返回值是新加载的图像的句柄。

Windows API 控件 I - 图2

Static image control

按钮

按钮是带有文本标签的简单控件。 用于触发动作。 当我们单击一个按钮时,它会向其父窗口发送WM_COMMAND消息。 wParam参数的低位字包含控件标识符。

button.c

  1. #include <windows.h>
  2. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  3. #define ID_BEEP 1
  4. #define ID_QUIT 2
  5. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  6. PWSTR lpCmdLine, int nCmdShow) {
  7. MSG msg;
  8. WNDCLASSW wc = {0};
  9. wc.lpszClassName = L"Buttons";
  10. wc.hInstance = hInstance;
  11. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  12. wc.lpfnWndProc = WndProc;
  13. wc.hCursor = LoadCursor(0, IDC_ARROW);
  14. RegisterClassW(&wc);
  15. CreateWindowW(wc.lpszClassName, L"Buttons",
  16. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  17. 150, 150, 300, 200, 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,
  25. WPARAM wParam, LPARAM lParam) {
  26. switch(msg) {
  27. case WM_CREATE:
  28. CreateWindowW(L"Button", L"Beep",
  29. WS_VISIBLE | WS_CHILD ,
  30. 20, 50, 80, 25, hwnd, (HMENU) ID_BEEP, NULL, NULL);
  31. CreateWindowW(L"Button", L"Quit",
  32. WS_VISIBLE | WS_CHILD ,
  33. 120, 50, 80, 25, hwnd, (HMENU) ID_QUIT, NULL, NULL);
  34. break;
  35. case WM_COMMAND:
  36. if (LOWORD(wParam) == ID_BEEP) {
  37. MessageBeep(MB_OK);
  38. }
  39. if (LOWORD(wParam) == ID_QUIT) {
  40. PostQuitMessage(0);
  41. }
  42. break;
  43. case WM_DESTROY:
  44. PostQuitMessage(0);
  45. break;
  46. }
  47. return DefWindowProcW(hwnd, msg, wParam, lParam);
  48. }

在我们的示例中,我们创建了两个按钮。 一键鸣音。 另一个将关闭窗口。

  1. CreateWindowW(L"Button", L"Beep",
  2. WS_VISIBLE | WS_CHILD ,
  3. 20, 50, 80, 25, hwnd, (HMENU) ID_BEEP, NULL, NULL);

按钮控件是使用L"Button"类创建的。

  1. case WM_COMMAND:
  2. if (LOWORD(wParam) == ID_BEEP) {
  3. MessageBeep(MB_OK);
  4. }
  5. if (LOWORD(wParam) == ID_QUIT) {
  6. PostQuitMessage(0);
  7. }
  8. break;

控件的 ID 在wParamLOWORD中。 根据 ID,我们称为MessageBeep()函数或PostQuitMessage()函数。

Windows API 控件 I - 图3

Button controls

CheckBox

复选框控件是可以单击以打开或关闭选项的框。

checkbox.c

  1. #include <windows.h>
  2. #include <stdbool.h>
  3. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  4. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  5. PWSTR lpCmdLine, int nCmdShow) {
  6. MSG msg;
  7. WNDCLASSW wc = {0};
  8. wc.lpszClassName = L"Check Box";
  9. wc.hInstance = hInstance ;
  10. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  11. wc.lpfnWndProc = WndProc;
  12. wc.hCursor = LoadCursor(0, IDC_ARROW);
  13. RegisterClassW(&wc);
  14. CreateWindowW(wc.lpszClassName, L"Check Box",
  15. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  16. 150, 150, 230, 150, 0, 0, hInstance, 0);
  17. while (GetMessage(&msg, NULL, 0, 0)) {
  18. TranslateMessage(&msg);
  19. DispatchMessage(&msg);
  20. }
  21. return (int) msg.wParam;
  22. }
  23. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  24. WPARAM wParam, LPARAM lParam) {
  25. bool checked = true;
  26. switch(msg) {
  27. case WM_CREATE:
  28. CreateWindowW(L"button", L"Show Title",
  29. WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
  30. 20, 20, 185, 35, hwnd, (HMENU) 1,
  31. NULL, NULL);
  32. CheckDlgButton(hwnd, 1, BST_CHECKED);
  33. break;
  34. case WM_COMMAND:
  35. checked = IsDlgButtonChecked(hwnd, 1);
  36. if (checked) {
  37. CheckDlgButton(hwnd, 1, BST_UNCHECKED);
  38. SetWindowTextW(hwnd, L"");
  39. } else {
  40. CheckDlgButton(hwnd, 1, BST_CHECKED);
  41. SetWindowTextW(hwnd, L"Check Box");
  42. }
  43. break;
  44. case WM_DESTROY:
  45. PostQuitMessage(0);
  46. break;
  47. }
  48. return DefWindowProcW(hwnd, msg, wParam, lParam);
  49. }

在我们的示例中,我们根据复选框的状态显示或隐藏窗口标题。

  1. CreateWindowW(L"button", L"Show Title",
  2. WS_VISIBLE | WS_CHILD | BS_CHECKBOX,
  3. 20, 20, 185, 35, hwnd, (HMENU) 1,
  4. NULL, NULL);

复选框是一种特殊的按钮。 它是用BS_CHECKBOX标志创建的。

  1. checked = IsDlgButtonChecked(hwnd, 1);

我们使用IsDlgButtonChecked()函数确定复选框的状态。

  1. CheckDlgButton(hwnd, 1, BST_UNCHECKED);

我们使用CheckDlgButton()函数选中并取消选中该复选框。

  1. SetWindowTextW(hwnd, L"");

SetWindowTextW()函数设置窗口的标题。

Windows API 控件 I - 图4

Checkbox control

编辑控件

编辑控件是一个矩形子窗口,用于输入和编辑文本。 它可以是单行或多行。

edit.c

  1. #include <windows.h>
  2. #define ID_EDIT 1
  3. #define ID_BUTTON 2
  4. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  5. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  6. PWSTR lpCmdLine, int nCmdShow) {
  7. MSG msg;
  8. WNDCLASSW wc = {0};
  9. wc.lpszClassName = L"Edit control";
  10. wc.hInstance = hInstance;
  11. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  12. wc.lpfnWndProc = WndProc;
  13. wc.hCursor = LoadCursor(0, IDC_ARROW);
  14. RegisterClassW(&wc);
  15. CreateWindowW(wc.lpszClassName, L"Edit control",
  16. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  17. 220, 220, 280, 200, 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,
  25. WPARAM wParam, LPARAM lParam) {
  26. static HWND hwndEdit;
  27. HWND hwndButton;
  28. switch(msg) {
  29. case WM_CREATE:
  30. hwndEdit = CreateWindowW(L"Edit", NULL,
  31. WS_CHILD | WS_VISIBLE | WS_BORDER,
  32. 50, 50, 150, 20, hwnd, (HMENU) ID_EDIT,
  33. NULL, NULL);
  34. hwndButton = CreateWindowW(L"button", L"Set title",
  35. WS_VISIBLE | WS_CHILD, 50, 100, 80, 25,
  36. hwnd, (HMENU) ID_BUTTON, NULL, NULL);
  37. break;
  38. case WM_COMMAND:
  39. if (HIWORD(wParam) == BN_CLICKED) {
  40. int len = GetWindowTextLengthW(hwndEdit) + 1;
  41. wchar_t text[len];
  42. GetWindowTextW(hwndEdit, text, len);
  43. SetWindowTextW(hwnd, text);
  44. }
  45. break;
  46. case WM_DESTROY:
  47. PostQuitMessage(0);
  48. break;
  49. }
  50. return DefWindowProcW(hwnd, msg, wParam, lParam);
  51. }

在我们的示例中,我们有一个编辑控件和一个按钮。 我们可以将一些文本放入编辑控件中。 如果单击按钮,则输入的文本将显示在主窗口的标题栏中。

  1. hwndEdit = CreateWindowW(L"Edit", NULL,
  2. WS_CHILD | WS_VISIBLE | WS_BORDER,
  3. 50, 50, 150, 20, hwnd, (HMENU) ID_EDIT,
  4. NULL, NULL);

编辑控件是使用L"Edit"窗口类创建的。 WS_BORDER窗口样式在控件周围创建细线边框。

  1. if (HIWORD(wParam) == BN_CLICKED) {
  2. int len = GetWindowTextLengthW(hwndEdit) + 1;
  3. wchar_t text[len];
  4. GetWindowTextW(hwndEdit, text, len);
  5. SetWindowTextW(hwnd, text);
  6. }

GetWindowTextLengthW()返回输入文本的长度。 注意,我们在长度上加 1。 这将包括零终止符。 尝试忽略它,看看会发生什么。 GetWindowTextW()从编辑控件接收文本。 该函数的第一个参数是包含文本的窗口或控件的句柄。 SetWindowTextW()设置窗口的文本。 在这种情况下,它是主窗口的标题。

Windows API 控件 I - 图5

图:编辑控件

在 Windows API 教程的这一部分中,我们介绍了四个基本的 Windows 控件。