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

在这里,我们将演示如何创建自己的自定义控件。 Windows API 具有各种预先构建的控件的集合。 必须手动创建更多特定的控件。 我们使用 GDI 创建自定义控件。

刻录控件

可以在各种媒体刻录应用中找到此控件,例如 Nero 刻录 ROM。

  1. #include <windows.h>
  2. #include <commctrl.h>
  3. #include <wchar.h>
  4. LRESULT CALLBACK PanelProc(HWND, UINT, WPARAM, LPARAM);
  5. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  6. HINSTANCE g_hinst;
  7. LRESULT g_pos = 150;
  8. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  9. PWSTR lpCmdLine, int nCmdShow)
  10. {
  11. HWND hwnd;
  12. MSG msg;
  13. WNDCLASSW wc = {0};
  14. wc.lpszClassName = L"Application";
  15. wc.hInstance = hInstance;
  16. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  17. wc.lpfnWndProc = WndProc;
  18. wc.hCursor = LoadCursor(0, IDC_ARROW);
  19. g_hinst = hInstance;
  20. RegisterClassW(&wc);
  21. hwnd = CreateWindowW(wc.lpszClassName, L"Burning control",
  22. WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
  23. 100, 100, 400, 250, 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. {
  32. static HWND hwndTrack, hwndBurn;
  33. WNDCLASSW rwc = {0};
  34. INITCOMMONCONTROLSEX InitCtrlEx;
  35. InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
  36. InitCtrlEx.dwICC = ICC_BAR_CLASSES;
  37. InitCommonControlsEx(&InitCtrlEx);
  38. switch(msg)
  39. {
  40. case WM_CREATE:
  41. rwc.lpszClassName = L"BurningControl";
  42. rwc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
  43. rwc.style = CS_HREDRAW;
  44. rwc.lpfnWndProc = PanelProc;
  45. rwc.hCursor = LoadCursor(0, IDC_ARROW);
  46. RegisterClassW(&rwc);
  47. hwndBurn = CreateWindowExW(WS_EX_STATICEDGE , L"BurningControl", NULL,
  48. WS_CHILD | WS_VISIBLE, 0, 330, 490, 30, hwnd, (HMENU)1, NULL, NULL);
  49. hwndTrack = CreateWindowExW(0, TRACKBAR_CLASSW, NULL,
  50. WS_CHILD | WS_VISIBLE | TBS_FIXEDLENGTH | TBS_NOTICKS,
  51. 40, 25, 150, 25, hwnd, (HMENU) 2, g_hinst, NULL);
  52. SendMessage(hwndTrack, TBM_SETRANGE, TRUE, MAKELONG(0, 750));
  53. SendMessage(hwndTrack, TBM_SETPAGESIZE, 0, 20);
  54. SendMessage(hwndTrack, TBM_SETTICFREQ, 20, 0);
  55. SendMessage(hwndTrack, TBM_SETPOS, TRUE, 150);
  56. break;
  57. case WM_SIZE:
  58. SetWindowPos(hwndBurn, NULL, 0, HIWORD(lParam)-30,
  59. LOWORD(lParam), 30, SWP_NOZORDER);
  60. break;
  61. case WM_HSCROLL:
  62. g_pos = SendMessage(hwndTrack, TBM_GETPOS, 0, 0);
  63. InvalidateRect(hwndBurn, NULL, TRUE);
  64. break;
  65. case WM_DESTROY:
  66. PostQuitMessage(0);
  67. break;
  68. }
  69. return DefWindowProcW(hwnd, msg, wParam, lParam);
  70. }
  71. LRESULT CALLBACK PanelProc(HWND hwnd, UINT msg,
  72. WPARAM wParam, LPARAM lParam)
  73. {
  74. HBRUSH hBrushYellow, hBrushRed, holdBrush;
  75. HPEN hPen, holdPen;
  76. HFONT hFont, holdFont;
  77. PAINTSTRUCT ps;
  78. RECT rect, rect2;
  79. wchar_t *cap[] = { L"75", L"150", L"225", L"300", L"375", L"450",
  80. L"525", L"600", L"675"};
  81. HDC hdc;
  82. int till;
  83. int step, full;
  84. int i;
  85. switch(msg)
  86. {
  87. case WM_PAINT:
  88. hdc = BeginPaint(hwnd, &ps);
  89. GetClientRect(hwnd, &rect);
  90. till = (rect.right / 750.0) * g_pos;
  91. step = rect.right / 10.0;
  92. full = (rect.right / 750.0) * 700;
  93. hBrushYellow = CreateSolidBrush(RGB(255, 255, 184));
  94. hBrushRed = CreateSolidBrush(RGB(255, 110, 110));
  95. hPen = CreatePen(PS_NULL, 1, RGB(0, 0, 0));
  96. holdPen = SelectObject(hdc, hPen);
  97. hFont = CreateFontW(13, 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0,
  98. 0, 0, 0, 0, L"Tahoma");
  99. holdFont = SelectObject(hdc, hFont);
  100. if(till > full) {
  101. SelectObject(hdc, hBrushYellow);
  102. Rectangle(hdc, 0, 0, full, 30);
  103. holdBrush = SelectObject(hdc, hBrushRed);
  104. Rectangle(hdc, full, 0, till, 30);
  105. } else {
  106. holdBrush = SelectObject(hdc, hBrushYellow);
  107. Rectangle(hdc, 0, 0, till, 30);
  108. }
  109. SelectObject(hdc, holdPen);
  110. for ( i = 1; i < 10; i++) {
  111. MoveToEx(hdc, i*step, 0, NULL);
  112. LineTo(hdc, i*step, 7);
  113. rect2.bottom = 28;
  114. rect2.top = 8;
  115. rect2.left = i*step-10;
  116. rect2.right = i*step+10;
  117. SetBkMode(hdc, TRANSPARENT) ;
  118. DrawTextW(hdc, cap[i-1], wcslen(cap[i-1]), &rect2, DT_CENTER);
  119. }
  120. SelectObject(hdc, holdBrush);
  121. DeleteObject(hBrushYellow);
  122. DeleteObject(hBrushRed);
  123. DeleteObject(hPen);
  124. SelectObject(hdc, holdFont);
  125. DeleteObject(hFont);
  126. EndPaint(hwnd, &ps);
  127. break;
  128. }
  129. return DefWindowProcW(hwnd, msg, wParam, lParam);
  130. }

在我们的示例中,我们显示一个轨迹栏控件和我们的自定义刻录控件。 跟踪栏控件用于控制刻录控件的状态。

刻录控件是一个简单的窗口。 它放置在父窗口的底部。 它在WM_PAINT消息期间被完全绘制。 使用 GDI 函数调用绘制线条,文本和背景。

Windows API 中的自定义控件 - 图1

图:刻录控件

在 Windows API 教程的这一部分中,我们创建了刻录自定义控件。