宣城网站开发网络公司,网站开发和网页设计,大连h5网站开发,滕王阁环境建设网站本系列博文几乎没有难啃的“专业术语”#xff0c;尽量让读者能够看明白文章所述内容#xff0c;是本系列博文的核心宗旨之一。#xff08;由于本人也是由于项目需要#xff0c;所以才来查阅相关资料#xff0c;文中出现的错误欢迎指出#xff0c;共同进步#xff01;谢…本系列博文几乎没有难啃的“专业术语”尽量让读者能够看明白文章所述内容是本系列博文的核心宗旨之一。由于本人也是由于项目需要所以才来查阅相关资料文中出现的错误欢迎指出共同进步谢谢
读本系列博文的读者必须具备以下的知识储备
C/C语言基础语法及了解面向对象概念
窗口在 Windows 中指一个矩形区域一般情况下这个区域是用户与应用程序交互的枢纽上一小节使用 MessageBox 创建的简单窗口也是与用户交互的一个窗口该窗口的功能有限只能够简单的展示一些想要表达的信息想创建一个能表达更多信息的窗口可以使用 CreateWindow 函数创建。
开始创建
创建 Windows 桌面应用程序需要 windows.h在头部引入 windows.h 头文件。
#include windows.h WinMain
在C语言中每个C语言程序都有一个入口函数在Windows桌面程序中这个入口函数是 WinMain 具体声明如下
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);在程序中紧接着在头部文件后我们使用 WinMain作为程序的入口函数
#include windows.h
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {}写好入口函数后必须要使用 RegisterClassEx 注册一个新的窗口类型再使用 CreateWindow 进行创建。
WNDCLASSEX
在注册新窗口前我们可以使用一个 WNDCLASSEX 结构用来描述创建的Windows这是窗口类微软开发中心对WNDCLASSEXA的描述“Contains window class information. It is used with the RegisterClassEx and GetClassInfoEx functions.”WNDCLASSEXA 是包含窗口信息的结构。语法如下
typedef struct tagWNDCLASSEXA {UINT cbSize;UINT style;WNDPROC lpfnWndProc;int cbClsExtra;int cbWndExtra;HINSTANCE hInstance;HICON hIcon;HCURSOR hCursor;HBRUSH hbrBackground;LPCSTR lpszMenuName;LPCSTR lpszClassName;HICON hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, *NPWNDCLASSEXA, *LPWNDCLASSEXA;结构成员
cbSize 窗口的大小为 WNDCLASSEX 这个结构的字节数大小赋值为 sizeof(WNDCLASSEX)style 窗口的风格为该窗口的样式取值为 CS_HREDRAW | CS_VREDRAWlpfnWndProc 窗口处理指针为指向窗体的的过程函数为指针使用 WndProc 处理应用程序在发生事件时从 Windows 接收的消息以下将会讲解 WndProccbClsExtra 窗口类结构后的附加字节数一般为0cbWndExtra 窗口事例后的附加字数一般为0hInstance 当前实例句柄直接把WinMain参数 hInstance表示当前实例句柄 赋值给 hInstance 即可hIcon 图标的句柄暂时赋值为NULLhCursor 光标的句柄使用 LoadCursor 加载光标以下讲解语法lpszClassName 类别名称的指针赋值为static TCHAR szWindowClass[] _T(CSDN 1_bit);hIconSm 窗口类关联的小图标使用 LoadIcon函数加载不过在文档中提示这个函数已过时可以使用 LoadImage 函数加载本篇使用的是 LoadIcon LoadImage 后面再做补充LoadIcon 函数语法将会在以下讲解hbrBackground 背景画刷的句柄将会在以下给出设置的值参考lpszMenuName 指向菜单资源名的指针为NULL即可
代码实现如下 WNDCLASSEX wcex;wcex.cbSize sizeof(WNDCLASSEX);wcex.style CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc WndProc;wcex.cbClsExtra 0;wcex.cbWndExtra 0;wcex.hInstance hInstance;wcex.hIcon LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor LoadCursor(NULL, IDC_CROSS);wcex.hbrBackground (HBRUSH)(COLOR_ACTIVECAPTION);wcex.lpszMenuName NULL;wcex.lpszClassName szWindowClass;wcex.hIconSm LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));——————————————————————————————————
WNDCLASSEX hbrBackground
值参考 ——————————————————————————————————
LoadCursor
LoadCursor 返回类型为 HCURSOR的语法如下
HCURSOR LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName
);参数说明
hInstance 可赋值当前实例lpCursorName要加载的游标资源的名称
在微软的参考文档中说明lpCursorName 的可设置为以下值 ——————————————————————————————————
lpfnWndProc
lpfnWndProc 为接收窗口处理的指针使用 WndProc 处理应用程序在发生事件时从 Windows 接收的消息。在微软的文档中写道“WndProc 是每个 Windows 桌面应用程序必须的窗口过程功能。 此函数通常命名为WndProc但您可以随心所欲地命名它。 例如如果用户在应用程序中选择确定按钮Windows 会向您发送消息您可以在WndProc函数内编写代码执行任何适当的操作。 这称为处理事件。 您只处理与应用程序相关的事件。WndProc 具有以下语法”如下。
LRESULT CALLBACK WndProc(_In_ HWND hWnd,_In_ UINT message,_In_ WPARAM wParam,_In_ LPARAM lParam
);那我们在程序中声明也如此声明那么定义如下使用微软文档示例
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{PAINTSTRUCT ps;HDC hdc;TCHAR greeting[] _T(Hello, 我是CSDN 1_bit 博客主页https://me.csdn.net/A757291228 );switch (message){case WM_PAINT:hdc BeginPaint(hWnd, ps);TextOut(hdc,5, 5,greeting, _tcslen(greeting));EndPaint(hWnd, ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);break;}return 0;
}在以上 WndProc 的实现中使用了 switch 语句在 switch 中判断了 WM_PAINT 消息WM_PAINT 消息为绘制主窗体在文档中写到 要处理的一条重要信息是WM_PAINT消息。 当必须更新其显示WM_PAINT窗口的一部分时应用程序将接收消息。 当用户在窗口前面移动窗口然后再次将其移开时可能会发生此事件。 您的应用程序不知道这些事件何时发生。 只有 Windows 知道因此它会通过消息WM_PAINT通知你的应用。 首次显示窗口时必须更新所有窗口。 要处理 WM_PAINT 消息首先应调用 BeginPaint然后处理所有的逻辑以在窗口中布局文本、按钮和其他控件然后调用 EndPaint。 ——————————————————————————————————
BeginPaint
BeginPaint 的语法为
HDC BeginPaint(HWND hWnd,LPPAINTSTRUCT lpPaint
);参数说明
HWND处理要重绘的窗口lpPaint接收绘制的接收绘画信息的 **PAINTSTRUCT**结构的指针
——————————————————————————————————
EndPaint 该调用EndPaint函数标记指定窗口画的结束。每次调用BeginPaint函数都需要此函数但是仅在绘制完成之后。 语法
BOOL EndPaint(HWND hWnd,const PAINTSTRUCT *lpPaint
);参数说明
hWnd处理的窗口lpPaint指向PAINTSTRUCT结构的指针
——————————————————————————————————
PostQuitMessage 向系统指示线程已请求终止退出。通常用于响应WM_DESTROY消息。 语法
void PostQuitMessage(int nExitCode
);参数说明
nExitCode应用程序退出代码。此值用作WM_QUIT消息的wParam参数。
——————————————————————————————————
DefWindowProc 调用默认窗口过程以为应用程序未处理的任何窗口消息提供默认处理。此功能确保处理所有消息。DefWindowProc用窗口过程接收到的相同参数调用。 语法
LRESULT LRESULT DefWindowProcA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam
);参数说明
hWnd窗口句柄Msg消息wParam附加消息lParam附加消息信息
——————————————————————————————————
TextOut 所述的TextOut函数在指定位置写入的字符串利用当前选择的字体背景颜色和文本颜色。 语法
BOOL TextOutW(HDC hdc,int x,int y,LPCWSTR lpString,int c
);参数说明
hdc上下文句柄x,y对齐字符串的xy坐标lpString字符串指针指向字符串c字符串长度
——————————————————————————————————
HDC
引用文档解释 HDC代码中是设备上下文的句柄这是 Windows 用于使应用程序与图形子系统通信的数据结构。 WM_DESTROY 销毁窗口时发送。从窗口中删除窗口后它将被发送到销毁窗口的窗口过程。 此消息首先发送到被销毁的窗口然后发送到被销毁的子窗口如果有。在处理消息期间可以假定所有子窗口仍然存在。 WM_DESTROY 在 WndProc 函数中使用
——————————————————————————————————
补充
WM_CREATE
当应用程序通过调用CreateWindowEx或CreateWindow函数请求创建窗口时发送。在函数返回之前发送消息。在创建窗口之后但在该窗口变为可见之前新窗口的窗口过程会收到此消息。
——————————————————————————————————
RegisterClassEx
之后注册该窗口使用 RegisterClassEx
RegisterClassEx(wcex);注册后使用 CreateWindow 进行注册的窗口创建语法如下
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标题名DWORD dwStyle窗口类型风格x,y初始位置x,ynWidth, nHeight初始尺寸hWndParent,窗体父级可为NULLhMenu菜单栏可为NULLhInstance当前实例lpParam应用程序使用可为NULL
创建窗体
HWND hWnd CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1000, 1000, NULL, NULL, hInstance, NULL);应用窗体名为 szWindowClass
static TCHAR szWindowClass[] _T(win32 Demo);应用窗体名为 szTitle
static TCHAR szTitle[] _T(This Win32);窗体风格类型为WS_OVERLAPPEDWINDOW 初始位置为CW_USEDEFAULT默认左上角出现 尺寸为1000, 1000 父级及菜单栏都为NULL hInstance为当前实例 hInstance lpParam应用程序使用为NULL
代码如下
#include windows.h
#include tchar.h static TCHAR szWindowClass[] _T(CSDN 1_bit);
static TCHAR szTitle[] _T(Win32 桌面应用程序);
HINSTANCE hInst;LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {WNDCLASSEX wcex;wcex.cbSize sizeof(WNDCLASSEX);wcex.style CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc WndProc;wcex.cbClsExtra 0;wcex.cbWndExtra 0;wcex.hInstance hInstance;wcex.hIcon LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor LoadCursor(NULL, IDC_CROSS);wcex.hbrBackground (HBRUSH)(COLOR_ACTIVECAPTION);wcex.lpszMenuName NULL;wcex.lpszClassName szWindowClass;wcex.hIconSm LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));RegisterClassEx(wcex);hInst hInstance;HWND hWnd CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{PAINTSTRUCT ps;HDC hdc;TCHAR greeting[] _T(Hello, 我是CSDN 1_bit 博客主页https://me.csdn.net/A757291228 );switch (message){case WM_PAINT:hdc BeginPaint(hWnd, ps);TextOut(hdc,5, 5,greeting, _tcslen(greeting));EndPaint(hWnd, ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);break;}return 0;
}——————————————————————————————————
ShowWindow
完成以上代码后还需使用 ShowWindow 让Windows窗体指定如何显示代码如下
ShowWindow(hWnd, nCmdShow);语法
BOOL ShowWindow(HWND hWnd,int nCmdShow
);参数说明
hWnd窗口句柄nCmdShow窗口的显示方式
nCmdShow 参考 ——————————————————————————————————
UpdateWindow
使用 UpdateWindow 发送 WM_PAINT 消息更新指定窗口。 语法
BOOL UpdateWindow(HWND hWnd
);参数
hWnd窗口句柄
整体代码如下
#include windows.h
#include tchar.h static TCHAR szWindowClass[] _T(CSDN 1_bit);
static TCHAR szTitle[] _T(Win32 桌面应用程序);
HINSTANCE hInst;LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {WNDCLASSEX wcex;wcex.cbSize sizeof(WNDCLASSEX);wcex.style CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc WndProc;wcex.cbClsExtra 0;wcex.cbWndExtra 0;wcex.hInstance hInstance;wcex.hIcon LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor LoadCursor(NULL, IDC_CROSS);wcex.hbrBackground (HBRUSH)(COLOR_ACTIVECAPTION);wcex.lpszMenuName NULL;wcex.lpszClassName szWindowClass;wcex.hIconSm LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));RegisterClassEx(wcex);hInst hInstance;HWND hWnd CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return 0;
}LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{PAINTSTRUCT ps;HDC hdc;TCHAR greeting[] _T(Hello, 我是CSDN 1_bit 博客主页https://me.csdn.net/A757291228 );switch (message){case WM_PAINT:hdc BeginPaint(hWnd, ps);TextOut(hdc,5, 5,greeting, _tcslen(greeting));EndPaint(hWnd, ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);break;}return 0;
}运行程序发现出现了一闪而过的窗口这个很像刚学习C语言的时候没有加上停止那我们就循环侦听 Windows 发送的消息即可
MSG msg;
while (GetMessage(msg, NULL, 0, 0))
{TranslateMessage(msg);DispatchMessage(msg);
}return (int) msg.wParam;——————————————————————————————————
GetMessage
GetMessage 从调用线程的消息队列中检索消息。该函数分派传入的已发送消息直到已发布的消息可供检索为止。 语法
BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax
);参数说明
lpMsg指向 MSG 结构的指针该结构从线程的消息队列接收消息信息。hWnd获取消息的的窗口句柄文档中解释到“如果hWnd为NULL则GetMessage检索属于当前线程的任何窗口的消息以及当前线程的消息队列中hwnd值为NULL的消息请参阅MSG结构。因此如果hWnd为NULL则将同时处理窗口消息和线程消息。”wMsgFilterMinwMsgFilterMax要检索的最低、最高消息值的整数值“**wMsgFilterMin 和 wMsgFilterMax 都为零则 GetMessage 返回所有可用消息**”
——————————————————————————————————
完整代码
#include windows.h
#include tchar.h static TCHAR szWindowClass[] _T(CSDN 1_bit);
static TCHAR szTitle[] _T(Win32 桌面应用程序);
HINSTANCE hInst;LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {WNDCLASSEX wcex;wcex.cbSize sizeof(WNDCLASSEX);wcex.style CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc WndProc;wcex.cbClsExtra 0;wcex.cbWndExtra 0;wcex.hInstance hInstance;wcex.hIcon LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));wcex.hCursor LoadCursor(NULL, IDC_CROSS);wcex.hbrBackground (HBRUSH)(COLOR_ACTIVECAPTION);wcex.lpszMenuName NULL;wcex.lpszClassName szWindowClass;wcex.hIconSm LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));RegisterClassEx(wcex);hInst hInstance;HWND hWnd CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);MSG msg;while (GetMessage(msg, NULL, 0, 0)){TranslateMessage(msg);DispatchMessage(msg);}return (int)msg.wParam;
}LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{PAINTSTRUCT ps;HDC hdc;TCHAR greeting[] _T(Hello, 我是CSDN 1_bit 博客主页https://me.csdn.net/A757291228 );switch (message){case WM_PAINT:hdc BeginPaint(hWnd, ps);TextOut(hdc,5, 5,greeting, _tcslen(greeting));EndPaint(hWnd, ps);break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, message, wParam, lParam);break;}return 0;
}运行结果如下