Win32编程之创建第一个windows窗口(一)
一、窗口创建过程
- 定义WinMain函数
- 定义窗口处理函数(自定义,处理消息)
- 注册窗口类(向操作系统写入一些数据)
- 创建窗口(内存中创建窗口)
- 显示窗口(绘制窗口的图像)
- 消息循环(获取/翻译/派发消息)
- 消息处理
示例代码:
#include <Windows.h>
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WindProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
//设计窗口类
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = hIns;
wc.lpfnWndProc = WindProc;
wc.lpszClassName = TEXT("Main");
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
//注册窗口类
RegisterClass(&wc);//将以上所有赋值全部写入操作系统
//在内存中创建窗口
HWND hWnd = CreateWindow(wc.lpszClassName, TEXT("Window"), WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);
//显示窗口
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
//消息循环
MSG nMsg = { 0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);//将按键消息转换为字符消息
DispatchMessage(&nMsg);//将消息分发给窗口处理函数
}
return 0;
}
二、字符编码
DBCS字符编码: A 我 是 程 序 员 01 0203 0405 0607 0809 0A0B 但是解析时,可能为: 01 0203 0405 0607 0809 0A0B 0102 0304 0506 0708 090A 0B UNICODE编码: A 我 是 程 序 员 0001 0203 0405 0607 0809 0A0B 不存在解析的问题
1.宽字节
- wchar_t:每个字符占2个字节,wchar_t实际上是unsigned shot类型,定义时,需要增加"L",通知编译器按照双字节编译字符串,采用UNICODE编码
- 需要使用支持wchar_t函数操作宽字节字符串,例如:wchar_t* pwszText = L"Hello wchar";wprint(L"%s\n", pwszText )
#include <Windows.h>
#include <stdio.h>
void C_Char() {
const char* pszText = "hello char";
printf("%s\n", pszText);
}
void W_Char() {
const wchar_t* pszText = L"hello wchar";
int len = wcslen(pszText);
wprintf(L"%s %d\n", pszText, len);
}
void T_Char() {
const TCHAR* pszText = TEXT("hello txt");
#ifdef UNICODE
wprintf(L"%s\n", pszText);
#else
printf("单:%s\n", pszText);
#endif
}
int main() {
W_Char();
C_Char();
T_Char();
system("pause");
return 0;
}
2.UNICODE字符的打印
wprintf对UNICODE字符打印支持不完善,可以在windows下使用WriteConsole API打印UNICODE字符
#include <Windows.h>
#include <stdio.h>
void PrintUnicode() {
const wchar_t* pszText = L"早上好";
//wprintf(L"%s\n", pszText);
//获取标准输出句柄
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsole(hOut, pszText, wcslen(pszText), NULL, NULL);
}
int main() {
PrintUnicode();
system("pause");
return 0;
}
三、窗口类的概念
- 窗口类包含了窗口的各种参数信息的数据结构
- 每个窗口都具有窗口类,基于窗口类创建窗口
- 每个窗口类都具有一个名称,使用前必须注册到系统
窗口类的分类:
- 系统已经定义好的窗口类,所有应用程序都可以直接使用
- 应用程序全局窗口类,当前应用程序所有模块都可以使用
- 应用程序局部窗口类,当前应用程序中本模块可以使用
1.系统窗口类
不要注册,直接使用窗口类即可,系统已经注册好了
例如:按钮-BUTTON、编辑框-EDIT
#include <Windows.h>
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
//在内存中创建窗口
HWND hWnd = CreateWindow(TEXT("Button"), TEXT("Window"), WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);
//显示窗口
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
//消息循环
MSG nMsg = { 0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);//将按键消息转换为字符消息
DispatchMessage(&nMsg);//将消息分发给窗口处理函数
}
return 0;
}
2.全局及局部窗口类
注册窗口类的函数:
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
lpWndClass:窗口类的数据,注册成功后,返回一个数字标识
注册窗口类的结构体:
typedef struct tagWNDCLASSA {
UINT style;//窗口类的风格
WNDPROC lpfnWndProc;//窗口处理函数
int cbClsExtra;//窗口类的附件数据buff的大小
int cbWndExtra;//窗口的附件数据buff的大小
HINSTANCE hInstance;//当前模块的实例句柄
HICON hIcon;//窗口图标句柄
HCURSOR hCursor;//鼠标的句柄
HBRUSH hbrBackground;//绘制窗口背景的画刷句柄
LPCSTR lpszMenuName;//窗口菜单的资源ID字符串
LPCSTR lpszClassName;//窗口类的名称
} WNDCLASSA
style窗口类风格:
应用程序全局窗口类的注册,需要在窗口类的风格中增加CS_GLOBALCLASS
例如:
WNDCLASS wce = {0};
wce.style = ...|CS_GLOBALCLASS;
应用程序局部窗口类:在注册窗口类时,不添加CS_GLOBALCLASS风格
- CS_HREDRAW:当窗口水平变化时,窗口重新绘制
- CS_VREDRAW:当窗口垂直变化时,窗口重新绘制
- CS_DBLCLKS:允许窗口接收鼠标双击
- CS_NOCLOSE:窗口没有关闭按钮
四、创建窗口
WINUSERAPI HWND WINAPI CreateWindowExA(
_In_ DWORD dwExStyle,//窗口的扩展风格
_In_opt_ LPCSTR lpClassName,//已经注册的窗口类名称
_In_opt_ LPCSTR lpWindowName,//窗口标题栏的名字
_In_ DWORD dwStyle,//窗口的基本风格
_In_ int X,//窗口左上角水平坐标位置
_In_ int Y,//窗口左上角垂直坐标位置
_In_ int nWidth,//窗口的宽度
_In_ int nHeight,//窗口的高度
_In_opt_ HWND hWndParent,//窗口的父窗口句柄
_In_opt_ HMENU hMenu,//窗口菜单的句柄
_In_opt_ HINSTANCE hInstance,//应用程序实例句柄
_In_opt_ LPVOID lpParam);//窗口创建附件参数
窗口的创建可以使用CreateWindow或CreateWindowExA,若是窗口创建成功则返回窗口句柄
CreateWindow函数执行流程:
- 系统根据传入的窗口名称,在应用程序局部窗口类中查找,如果找到执行第二步,如果未找到则执行第三步
- 比较局部窗口类与创建窗口时传入的HINSTANCE变量,如果发现相等,创建和注册的窗口类在同一模块,创建窗口返回,如果不相等,则继续执行第三步
- 在应用程序全局窗口类,如果找到,执行第四部,如果未找到则执行第5步
- 使用找到的窗口类的信息,创建窗口返回
- 在系统窗口类中查找,如果找到创建窗口返回,否则创建窗口失败
函数内部大致执行流程:
if (找到窗口类) {
申请一大块内存,将窗口的数据信息存入这块内存
return 这块内存的句柄
} else {
return NULL
}
五、子窗口的创建
- 创建时要设置父窗口句柄
- 创建风格要增减WS_CHILD|WS_VISIBLE
#include <Windows.h>
//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WindProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam) {
switch (msgID) {
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, msgID, wParam, lParam);
}
//入口函数
int CALLBACK WinMain(HINSTANCE hIns, HINSTANCE hPreIns, LPSTR lpCmdLine, int nCmdShow) {
//设计窗口类
WNDCLASS wc = { 0 };
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = hIns;
wc.lpfnWndProc = WindProc;
wc.lpszClassName = TEXT("Main");
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
//注册窗口类
RegisterClass(&wc);//将以上所有赋值全部写入操作系统
//在内存中创建窗口
HWND hWnd = CreateWindow(wc.lpszClassName, TEXT("Window"), WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hIns, NULL);
//设计子窗口类
WNDCLASS wcChild = { 0 };
wcChild.cbClsExtra = 0;
wcChild.cbWndExtra = 0;
wcChild.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcChild.hCursor = NULL;
wcChild.hIcon = NULL;
wcChild.hInstance = hIns;
wcChild.lpfnWndProc = DefWindowProc;
wcChild.lpszClassName = TEXT("Child");
wcChild.lpszMenuName = NULL;
wcChild.style = CS_HREDRAW | CS_VREDRAW;
//注册子窗口类
RegisterClass(&wcChild);
//创建子窗口
HWND hChildWnd = CreateWindowEx(0, wcChild.lpszClassName, TEXT("SubWindow"), WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0, 0, 200, 200, hWnd, NULL, hIns, NULL);
HWND hChildWnd1 = CreateWindowEx(0, wcChild.lpszClassName, TEXT("SubWindow1"), WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW, 200, 0, 200, 200, hWnd, NULL, hIns, NULL);
//显示窗口
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
//消息循环
MSG nMsg = { 0 };
while (GetMessage(&nMsg, NULL, 0, 0)) {
TranslateMessage(&nMsg);//将按键消息转换为字符消息
DispatchMessage(&nMsg);//将消息分发给窗口处理函数
}
return 0;
}

浙公网安备 33010602011771号