api (二) 创建控件 (转)
在Win32 SDK环境下,怎么来创建常用的那些基本控件呢?我们知道如果用MFC,简单的拖放即可完成大多数控件的创建,但是我们既然是用Windows SDK API编程,当然是从根上解决这个问题,实际上MFC的下层也是通过这些API完成的。
实际上控件也是窗口,只不过是被微软预先创建好的一种窗口类,比如button就是一个类名为“BUTTON”的类。既然控件实际上是窗口,当然也是用CreateWindow或者CreateWindowEx这个函数来完成的,第二个函数除了多一个扩展风格之外,其他完全一样,下面以主要以CreateWindow为例说明,该函数原型如下(实际上在第一篇已经讲过了):
1
2
3
4
5
6
7
8
9
|
HWND CreateWindow(LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent,
HMENU hMenu,
HANDLE hInstance,
PVOID lpParam
);
|
lpClassName:控件的类名
lpWindowName:控件的名字或者文本
dwStyle:控件风格
x,y,nWidth,nHeight:控件的坐标和宽高
hWndParent:控件的父窗口
hMenu:控件的ID
hInstance:控件设置为空
lpParam:控件设为空
那么具体怎么实现各个基本的控件呢?下面我们来先依次举例。
- 创建标签/静态文本
1
|
CreateWindow(TEXT("STATIC"), TEXT("Test String"), WS_CHILD|WS_VISIBLE, 10, 10, 80, 20, hWnd, (HMENU)IDC_STATIC1, NULL, NULL);
|
- 创建button
1
|
CreateWindow(TEXT("BUTTON"), TEXT("Click Me"), WS_CHILD|WS_VISIBLE, 10, 40, 80, 20, hWnd, (HMENU)IDC_BUTTON1, NULL, NULL);
|
- 创建编辑框
1
|
CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), NULL, WS_CHILD|WS_VISIBLE|WS_BORDER, 10, 70, 80, 20, hWnd, (HMENU)IDC_EDIT1, NULL, NULL);
|
- 创建Groupbox
1
|
CreateWindow(TEXT("BUTTON"), TEXT("frame"), WS_CHILD|WS_VISIBLE|BS_GROUPBOX, 120, 10, 130, 50, hWnd, (HMENU)IDC_FRAME1, NULL, NULL);
|
- 创建单选框
1
|
CreateWindow(TEXT("BUTTON"), TEXT("radio button"), WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON, 134, 30, 40, 20, hWnd, (HMENU)IDC_MALE, NULL, NULL);
|
- 创建复选框
1
|
CreateWindow(TEXT("BUTTON"), TEXT("红色"), WS_CHILD|WS_VISIBLE|BS_CHECKBOX|BS_AUTOCHECKBOX, 120, 70, 54, 20, hWnd, (HMENU)IDC_CKBRED, NULL, NULL);
|
- 创建列表框
1
|
CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("LISTBOX"), NULL, WS_CHILD|WS_VISIBLE|LBS_STANDARD, 10, 100, 80, 90, hWnd, (HMENU)IDC_LISTBOX1, NULL, NULL);
|
- 创建组合框
1
|
CreateWindow(TEXT("COMBOBOX"), NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWNLIST, 120, 100, 100, 90, hWnd, (HMENU)IDC_CB1, NULL, NULL);
|
- 创建滚动条
1
|
CreateWindow(TEXT("SCROLLBAR"), NULL, WS_CHILD|WS_VISIBLE|SBS_HORZ, 10, 200, 200, 20, hWnd, (HMENU)IDC_SCB1, NULL, NULL);
|
以上创建各个控件都很差傻瓜化,你可以复制下来改改坐标、文本、风格、ID等就可以按照你的需要创建了。
下面我们就来实战一下,把这些常用的控件在程序中实现,下面我们来实现一个完整的windows程序,程序中包含了这些常用的控件和更多的用法。
/* 常用控件实例 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
#include <windows.h>
#define IDC_STATIC1 1001
#define IDC_BUTTON1 1002
#define IDC_EDIT1 1003
#define IDC_FRAME1 1004
#define IDC_MALE 2001
#define IDC_FEMALE 2002
#define IDC_LISTBOX1 1005
#define IDC_CB1 1006
#define IDC_CKBRED 1007
#define IDC_CKBGRN 1008
#define IDC_CKBBLU 1009
#define IDC_SCB1 1010
#define IDC_SCB2 1011
static TCHAR szAppName[] = TEXT("HelloWin32");
static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox (NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
hWnd = CreateWindow(szAppName, // window class name
szAppName, // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
400, // initial x size
300, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND hCtrl;
switch (message)
{
case WM_CREATE:
CreateWindow(TEXT("STATIC"), TEXT("Test String"), WS_CHILD|WS_VISIBLE, 10, 10, 80, 20, hWnd, (HMENU)IDC_STATIC1, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("Click Me"), WS_CHILD|WS_VISIBLE, 10, 40, 80, 20, hWnd, (HMENU)IDC_BUTTON1, NULL, NULL);
CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), NULL, WS_CHILD|WS_VISIBLE|WS_BORDER, 10, 70, 80, 20, hWnd, (HMENU)IDC_EDIT1, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("性别"), WS_CHILD|WS_VISIBLE|BS_GROUPBOX, 120, 10, 130, 50, hWnd, (HMENU)IDC_FRAME1, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("男"), WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON, 134, 30, 40, 20, hWnd, (HMENU)IDC_MALE, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("女"), WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON, 194, 30, 40, 20, hWnd, (HMENU)IDC_FEMALE, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("红色"), WS_CHILD|WS_VISIBLE|BS_CHECKBOX|BS_AUTOCHECKBOX, 120, 70, 54, 20, hWnd, (HMENU)IDC_CKBRED, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("绿色"), WS_CHILD|WS_VISIBLE|BS_CHECKBOX|BS_AUTOCHECKBOX, 180, 70, 54, 20, hWnd, (HMENU)IDC_CKBGRN, NULL, NULL);
CreateWindow(TEXT("BUTTON"), TEXT("蓝色"), WS_CHILD|WS_VISIBLE|BS_CHECKBOX|BS_AUTOCHECKBOX, 240, 70, 54, 20, hWnd, (HMENU)IDC_CKBBLU, NULL, NULL);
hCtrl = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("LISTBOX"), NULL, WS_CHILD|WS_VISIBLE|LBS_STANDARD, 10, 100, 80, 90, hWnd, (HMENU)IDC_LISTBOX1, NULL, NULL);
SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)TEXT("list str1"));
SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)TEXT("list str2"));
SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)TEXT("list str3"));
SendMessage(hCtrl, LB_ADDSTRING, 0, (LPARAM)TEXT("list str4"));
hCtrl = CreateWindow(TEXT("COMBOBOX"), NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL|CBS_DROPDOWNLIST, 120, 100, 100, 90, hWnd, (HMENU)IDC_CB1, NULL, NULL);
SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)TEXT("comb str1"));
SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)TEXT("comb str2"));
SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)TEXT("comb str3"));
SendMessage(hCtrl, CB_ADDSTRING, 0, (LPARAM)TEXT("comb str4"));
SendMessage(hCtrl, CB_SETCURSEL, 1, 0);
CreateWindow(TEXT("SCROLLBAR"), NULL, WS_CHILD|WS_VISIBLE|SBS_HORZ, 10, 200, 200, 20, hWnd, (HMENU)IDC_SCB1, NULL, NULL);
CreateWindow(TEXT("SCROLLBAR"), NULL, WS_CHILD|WS_VISIBLE|SBS_VERT, 240, 100, 20, 120, hWnd, (HMENU)IDC_SCB2, NULL, NULL);
return 0;
case WM_COMMAND:
{
HWND hwndTmp;
int wmId = LOWORD(wParam);
switch (wmId)
{
case IDC_BUTTON1:
hwndTmp = GetDlgItem(hWnd, IDC_STATIC1);
SetWindowText(hwndTmp, TEXT("New Text"));
MessageBox(hWnd, TEXT("Text Changed!"), TEXT("info"), MB_OK);
break;
}
}
return 0;
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC)wParam;
SetTextColor(hdc, RGB(0xFF, 0x00, 0x00));
}
return (BOOL)((HBRUSH)GetStockObject(NULL_BRUSH));
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
|
编译一下运行,结果如下:
怎么样,是不是很简单,虽然我们的控件创建比MFC麻烦一下,但是我们是从“根”上来解决问题的,感觉是不一样的!有了这些基本的用法,你就可以构建更加复制的Windows界面了。赶快去试试吧。