Windows基本元素:控件 Windows中将按钮、复选框等作为组件使用的东西称为控件。本页面将介绍这些的使用方法。 基本的控件根据其窗口类名可以分为静态控件、按钮控件、编辑控件、列表框控件、组合框控件以及滚动条控件六种。
1.静态控件
静态控件虽然也能显示位图,但主要是用来仅显示文字的简单控件。用于显示标签等。可以是多行文本,文本的右端自动换行。但是,不带有滚动功能。下面展示了程序示例及其运行画面。
Static01.c
#include <windows.h>
#include <string.h>
#define WND_CLASS_NAME "My_Window"
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
WNDCLASS wcl;
MSG msg;
char *text = "在长句子中,右端的折返是自动完成的。 但是,没有滚动功能";
memset(&wcl, 0, sizeof(wcl));
wcl.hInstance = hInstance;
wcl.lpszClassName = WND_CLASS_NAME;
wcl.lpfnWndProc = WindowProc;
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
if (!RegisterClass(&wcl)) return FALSE;
hWnd = CreateWindowEx(0, WND_CLASS_NAME, "Windows Programming",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10, 10, 400, 150, NULL, NULL, hInstance, NULL);
if(!hWnd) return FALSE;
CreateWindowEx(0, "STATIC", "即使这样\n窗口", WS_CHILD | WS_VISIBLE | WS_BORDER,
10, 10, 150, 50, hWnd, (HMENU)1, hInstance, NULL);
CreateWindowEx(0, "STATIC", text, WS_CHILD | WS_VISIBLE,
170, 10, 200, 80, hWnd, (HMENU)1, hInstance, NULL);
while (GetMessage(&msg,NULL,0,0) > 0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
2.按钮控件
定义好的按钮等控件类不需要设置WNDCLASS。此外,按钮被按下时的绘制处理和消息处理都是默认支持的,因此无需进行任何设置。 这些控件通过在CreateWindow()函数的样式中指定WS_CHILD,并注册为当前窗口的子窗口。另外,在第8个参数hWndParent中,指定作为所有者的父窗口句柄。位置是根据所有者窗口的客户区坐标来确定的。下面展示了程序和运行结果。
Intro31x.c
#include <windows.h>
#include <stdio.h>
#include <string.h>
#define WND_CLASS_NAME "My_Window"
#define BID_1 0
#define BID_2 1
int nBtn = 0;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
char buf[256];
switch (uMsg) {
case WM_COMMAND:
nBtn = wParam;
switch(wParam) {
case BID_1:
MessageBox(hwnd, "按下按钮1", "Button", MB_OK);
break;
case BID_2:
MessageBox(hwnd, "按钮2被按下了", "Button", MB_OK);
break;
}
sprintf(buf, "ButtonAA %d", nBtn);
SetWindowText(hwnd, buf);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
WNDCLASS wcl;
MSG msg;
memset(&wcl, 0, sizeof(wcl));
wcl.hInstance = hInstance;
wcl.lpszClassName = WND_CLASS_NAME;
wcl.lpfnWndProc = WindowProc;
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
if (!RegisterClass(&wcl)) return FALSE;
hWnd = CreateWindowEx(0, WND_CLASS_NAME, "Windows Programming",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10, 10, 400, 100, NULL, NULL, hInstance, NULL);
if(!hWnd) return FALSE;
CreateWindowEx(0, "BUTTON", "按钮1", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0, 0, 100, 50, hWnd, (HMENU)0, hInstance, NULL);
CreateWindowEx(0, "BUTTON", "按钮2", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
110, 0, 100, 50, hWnd, (HMENU)1, hInstance, NULL);
while (GetMessage(&msg,NULL,0,0) > 0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
当有多个按钮时,如果想要像单选按钮那样,只能使其中一个有效,可能会希望知道当前哪个按钮被按下。这可以通过稍微修改CreateWindow函数的样式来实现。这本质上是将外观设为按钮样式(BS_PUSHLIKE)的单选按钮。
Intro32a.c
// tcc intro32.c ../lib/winlib.o
#include <windows.h>
#include <stdio.h>
#include <string.h>
#define WND_CLASS_NAME "My_Window"
#define BID_1 0
#define BID_2 1
#define BID_3 2
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_COMMAND:
switch(wParam) {
case BID_1:
MessageBox(hwnd, "按下按钮1", "Button", MB_OK);
break;
case BID_2:
MessageBox(hwnd, "按钮2被按下了", "Button", MB_OK);
break;
case BID_3:
MessageBox(hwnd, "按下按钮3", "Button", MB_OK);
break;
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
HWND hWnd;
WNDCLASS wcl;
MSG msg;
memset(&wcl, 0, sizeof(wcl));
wcl.hInstance = hInstance;
wcl.lpszClassName = WND_CLASS_NAME;
wcl.lpfnWndProc = WindowProc;
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
if (!RegisterClass(&wcl)) return FALSE;
hWnd = CreateWindowEx(0, WND_CLASS_NAME, "Windows Programming",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10, 10, 350, 100, NULL, NULL, hInstance, NULL);
if(!hWnd) return FALSE;
CreateWindowEx(0, "BUTTON", "按钮1",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | BS_PUSHLIKE | WS_GROUP,
0, 0, 100, 50, hWnd, (HMENU)BID_1, hInstance, NULL);
CreateWindowEx(0, "BUTTON", "按钮2",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | BS_PUSHLIKE,
110, 0, 100, 50, hWnd, (HMENU)BID_2, hInstance, NULL);
CreateWindowEx(0, "BUTTON", "按钮3",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | BS_PUSHLIKE,
220, 0, 100, 50, hWnd, (HMENU)BID_3, hInstance, NULL);
while (GetMessage(&msg,NULL,0,0) > 0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
当按钮较多时,使用数组会比较方便。最初,要使某个按钮处于被按下状态,可以使用SendMessage函数。下面的程序设置了按下按钮时改变背景色。
Intro33a.c
#include <windows.h>
#include <stdio.h>
#include <string.h>
#define WND_CLASS_NAME "My_Window"
char *btn[] = { "红色", "蓝色", "绿色", "白色", "黑色" };
COLORREF color[] = { 0xFF, 0xFF0000, 0xFF00, 0xFFFFFF, 0x0 };
int idBtn; // 选择中的按钮号码
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
HBRUSH hBrush;
RECT rect;
switch (uMsg) {
case WM_COMMAND:
idBtn = wParam;
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_PAINT:
GetClientRect(hwnd, &rect);
hdc = BeginPaint(hwnd, &ps)