C++ 创建一个窗口采用GDI的方式绘制文字
跟Winform和WPF不太一样的创建方式,是基于Windows 系统API的方式,这也是Windows系统编程的一部分,这种方式很底层了算是。
创建项目
windows 桌面向导
直接创建
创建main.cpp
#include <windows.h>//定义窗口宽度
int WINDOW_WIDTH = 800;
//定义当前文本绘制的宽度位置
int CurrentWidth = 0;
// 窗口过程函数声明
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);// 程序入口点
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{// 1. 注册窗口类const wchar_t CLASS_NAME[] = L"Sample Window Class";WNDCLASS wc = { 0 };wc.lpfnWndProc = WindowProc; // 窗口过程函数wc.hInstance = hInstance; // 实例句柄wc.lpszClassName = CLASS_NAME; // 窗口类名wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 背景色RegisterClass(&wc);// 2. 创建窗口HWND hwnd = CreateWindowEx(0, // 扩展样式CLASS_NAME, // 窗口类名L"我的第一个窗口", // 窗口标题WS_OVERLAPPEDWINDOW, // 窗口样式(带标题栏、边框、最大化/最小化按钮)// 窗口位置和大小CW_USEDEFAULT, CW_USEDEFAULT, // 初始x、y坐标(使用默认值)WINDOW_WIDTH, 600, // 宽度和高度NULL, // 父窗口句柄NULL, // 菜单句柄hInstance, // 实例句柄NULL // 附加数据);if (hwnd == NULL){return 0; // 创建窗口失败}// 3. 显示窗口ShowWindow(hwnd, nCmdShow);// 4. 消息循环MSG msg = { 0 };while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg); // 翻译键盘消息DispatchMessage(&msg); // 分发消息到窗口过程}return 0;
}// 窗口过程(处理窗口消息)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{switch (uMsg){case WM_CREATE:// 设置1秒定时器(ID为1)SetTimer(hwnd, 1, 1000, NULL);break;case WM_TIMER:// 定时器触发(wParam 为定时器ID,这里判断是否是我们设置的ID=1)if (wParam == 1) {CurrentWidth += 10;if (CurrentWidth >= (WINDOW_WIDTH -10))//如果宽度超过窗口宽度,重置为0{CurrentWidth = 0;}// 每1秒触发一次重绘(标记整个客户区无效)InvalidateRect(hwnd, NULL, TRUE);}break;case WM_DESTROY:PostQuitMessage(0); // 窗口关闭时发送退出消息return 0;case WM_PAINT:// 绘制窗口内容{PAINTSTRUCT ps;HDC hdc = BeginPaint(hwnd, &ps);// 绘制背景FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));// 绘制文本const wchar_t text[] = L"Hello, Win32!";TextOut(hdc, CurrentWidth, 50, text, wcslen(text));EndPaint(hwnd, &ps);return 0;}}// 处理未定义的消息(使用默认处理)return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
运行一下结果如下:
函数分析
其中最主要的就是CreateWindowEx创建窗口这个函数,除了ShowWindow显示窗口,还有SetWindowPos可以更加自定义的显示窗口(比如不能缩小方法等)
消息循环这一块除了阻塞获取消息的GetMessage实际上还可以用另外一个函数 PeekMessage 无阻塞的获取窗口消息
另外使用了一个定时为1秒的定时器 SetTimer(hwnd, 1, 1000, NULL); 它会每一秒触发窗口消息 WM_TIMER 类型
还有就是GDI的绘制函数部分 BeginPaint和 EndPaint.
逻辑分析
整体逻辑简单,创建一个窗口,然后,消息循环(维持消息泵)不让应用退出除非收到退出的窗口消息(比如点击X或者Ctrl+F4),然后,每一秒让窗体显示的文字移动10像素,移动到窗体最右侧就从头开始.
总结
一个最简单的C++窗口示例,细节实际上很多,用来学习基础WINApi还不错.
git仓库
https://github.com/kesshei/direct9Demo
https://gitee.com/kesshei/direct9Demo