使用C++编写一个可视化窗口

您所在的位置:网站首页 unix命令行界面 使用C++编写一个可视化窗口

使用C++编写一个可视化窗口

2023-08-23 06:09| 来源: 网络整理| 查看: 265

初学C++时,控制台会给我们提供一个黑窗口,而这篇文章所做的就是:创建一个属于图形界面窗口,而不是使用控制台黑窗口

如图,这是一个标题为XSZY的窗口 这都是自定义的 一个标题为XSZY的窗口

所有有关视窗的基本函数和类型都定义在头文件 中 我们只需要引用就好了

//引用头文件 windows.h #include

然后定义程序的入口函数main

int __stdcall WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow) {}

说到这个入口函数,其实使用main()也是可以的

int main() {} int main(int argc, char** argv) {} int main(int argc, char* argv[]) {}

其实C++定义了很多程序入口,只要程序中包含其中一个,程序就可以运行了

而WinMain的声明同样也是有依据可寻的

在头文件 中, 有这样两句话 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd); int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd); 它们分别声明了两种程序入口 WinMain 和 wWinMain wWinMain 是 WinMain 的宽字符版本, 形参列表中的LPWSTR说明了这个事实 顺带说一下吧 基本所有的函数、类型、结构体、宏等都带有A 和 W, 比如 WNDCLASSA 和 WNDCLASSW 一般A是窄字符, W是宽字符 LPSTR 其实就是 char* ; 而LPWSTR 是 wchar_t* 表示宽字符时需要标记L 比如定义宽字符串HelloWorld应该写为 L"HelloWorld!" ,系统就会识别为宽字符了

说了这么多,该定义窗口实例句柄了 这是用来指向一个实例( instance ) 的类型 HINSTANCE 前缀H就是Handle句柄的意思, instance就是实例的意思

这个句柄的作用就是:指定一个窗口实例

如果你使用的时WinMain,那么可以选择直接使用形参表中的第一个或第二个参数,但是如果你使用的时int main(),那么就需要定义一个新的实例句柄

int WINAPI WinMain(HINSTANCE hInst, //可以使用这个 HINSTANCE hPrev, //也可以使用这个(习惯上使用上面的) LPSTR lpCmdLine, int nShowCmd) {} int main() { HINSTANCE hInst; //定一个新的实例句柄 }

定义来有什么用呢? 我们需要做一个窗口,就需要创建它,而定义它的标准,是由结构体WNDCLASS来完成的,能够让窗口和窗口结构体链接上的,需要实例句柄一致,并且和窗口类名一致

窗口类在 中的定义

typedef struct tagWNDCLASSA { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; } WNDCLASSA,*PWNDCLASSA,*NPWNDCLASSA,*LPWNDCLASSA; typedef struct tagWNDCLASSW { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCWSTR lpszMenuName; LPCWSTR lpszClassName; } WNDCLASSW,*PWNDCLASSW,*NPWNDCLASSW,*LPWNDCLASSW;

我们需要对其成员进行填充, 不然编译器无法为它分配内存,就会报错的。

解释:style 是窗口样式 lpfnWndProc 是回调函数(等会再说) cbClsExtra 是窗口类拓展 一般无拓展 cbWndExtra 是窗口扩展 一般无拓展 hInstance 就是实例句柄,需要将其定义为我们刚刚定义的实例句柄 hIcon 窗口的图标

图标示意图

hCursor是鼠标 lpszMenuName 菜单名 一般为空 lpszClassName 窗口类名

现在可以把我们需要的赋值, 不需要的全部memset为0

WNDCLASSA wc; memset(&wc, 0, sizeof(wc)); wc.lpszClassName = "WindowClassName"; wc.hInstance = hInst; wc.lpfnWndProc = ; //回调函数

回调函数是用来处理消息的 在消息循环的过程中,消息被分发到回调函数,回调函数内的代码提供操作

定义回调函数

long long WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { return DefWindowProc(hwnd, msg, wp, lp); }

此时给lpfnWndProc复制只用函数名即可

wc.lpfnWndProc = WndProc;

定义窗口结构体也可以使用WNDCLASSEX(拓展过的窗口类)

WNDCLASSEXA wc; wc.cbSize = sizeof(WNDCLASSEXA); wc.hInstance = hinst; wc.lpfnWndProc = WndProc; wc.lpszClassName = "WindowClassName";

使用拓展类可以给成员cbSize赋值,就可以正确分配内存了

定义完窗口类,应该向Windows注册窗口,让它授权创建一个带有此窗口类的窗口 RegisterClassA(&wc);

注册完之后,就要将窗口创建到窗口句柄中了 窗口句柄类型 HWND 创建窗口的函数很长,如果你没有使用EX的结构体,创建窗口的函数大体如下

CreateWindow(窗口类名,窗口标题,窗口风格,窗口的位置x, y, 窗口宽, 窗口长,父窗口,菜单,实例句柄,附加函数); 窗口类名需要和窗口结构体的类名lpszClassName一致,实例句柄也必须引用同一个 CreateWindowA 和 CreateWindowW 的区别不用我重申了吧 如果你使用了WNDCLASSEX的结构体 那么创建窗口相应地得加上EX CreateWindowEx(窗口拓展风格,...);后面和CreateWindow一样,只是在CreateWindow的基础上在前面添加了一个拓展风格的形参,一般我会使用客户区的拓展(WS_EX_CLIENTEDGE)

代码:

HWND hwnd = CreateWindowA("WindowClassName", "XSZY", WS_OVERLAPPEDWINDOW, 100, 100, 640, 480, NULL, NULL, hInst, NULL);

其他的比较好理解,就是窗口风格是不是看不懂? 它是一个宏定义 一共有这些宏定义表示窗口的风格,要添加多个就使用按位OR(|)运算符就可以了

#define WS_OVERLAPPED __MSABI_LONG(0x00000000) //窗口的基本样式 #define WS_POPUP __MSABI_LONG(0x80000000) //弹出式窗口 #define WS_CHILD __MSABI_LONG(0x40000000) //子窗口(指嵌在主窗口内部的子窗口) #define WS_MINIMIZE __MSABI_LONG(0x20000000) //最小化 #define WS_VISIBLE __MSABI_LONG(0x10000000) //可见 #define WS_DISABLED __MSABI_LONG(0x08000000) #define WS_CLIPSIBLINGS __MSABI_LONG(0x04000000) #define WS_CLIPCHILDREN __MSABI_LONG(0x02000000) #define WS_MAXIMIZE __MSABI_LONG(0x01000000) //最大化 #define WS_CAPTION __MSABI_LONG(0x00C00000) //标题栏 #define WS_BORDER __MSABI_LONG(0x00800000) //边框 #define WS_DLGFRAME __MSABI_LONG(0x00400000) //对话框风格(只有一个叉叉) #define WS_VSCROLL __MSABI_LONG(0x00200000) //竖滚动轴 #define WS_HSCROLL __MSABI_LONG(0x00100000) //横滚动轴 #define WS_SYSMENU __MSABI_LONG(0x00080000) //系统菜单(如果只添加了这个风格就和对话框一样) #define WS_THICKFRAME __MSABI_LONG(0x00040000) //可变大小 #define WS_GROUP __MSABI_LONG(0x00020000) #define WS_TABSTOP __MSABI_LONG(0x00010000) #define WS_MINIMIZEBOX __MSABI_LONG(0x00020000) //最小化控件框 #define WS_MAXIMIZEBOX __MSABI_LONG(0x00010000) //最大化控件框 #define WS_TILED WS_OVERLAPPED #define WS_ICONIC WS_MINIMIZE #define WS_SIZEBOX WS_THICKFRAME #define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) #define WS_POPUPWINDOW (WS_POPUP | WS_BORDER | WS_SYSMENU) #define WS_CHILDWINDOW (WS_CHILD)

这里有可能会失败,所以添加一条判断:

if(hwnd == NULL) return -1;

如果你刚刚已经添加WS_VISIBLE 那么这一步可以省略 因为我这一步要设置窗口可见 ShowWindow函数就能够提供此功能

ShowWindow(hwnd, SW_SHOW);

SW_SHOW是一个宏,表示显示窗口 可用的还有SW_HIDE等宏,这里就不详细说了,可以在头文件 中找到

最后是消息循环 消息结构体是MSG 消息循环的三个函数都要用到MSG类 所以定义一个先

MSG msg;

消息循环的过程应该是获得消息–>处理消息–>执行操作三步,分别对应三个函数

获得消息GetMessage(LPMSG, HWND,UINT,UINT) 处理消息(编码处理)TranslateMessage(LPMSG) 执行操作要在回调函数里执行,但是我们需要将消息发送给回调函数,这个函数是DispatchMessage(LPMSG) LPMSG 理解为MSG的指针 为了不断处理消息,应该设置一个循环while(true) 在它的循环体内,写一个判断:如果收到消息,处理并分发消息 代码如下 while(true) if(GetMessage(&msg, NULL, 0, 0) { TranslateMessage(&msg); DispatchMessage(&msg); }

HWND之所以没有锁定为hwnd,是因为别的消息它也要接受的

消息发到回调函数了,但是回调函数现在还是这样的:

long long WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { return DefWindowProc(hwnd, msg, wp, lp); }

并不能处理消息。 消息传过去后,msg,wp,lp三个参数负责接收消息,而msg是区分各个消息的 现在先让我们处理窗口关闭的消息,不然关不了 做法很简单,在return上面加上一个switch来分发消息(当然你用if else if 也行)

switch(msg) { }

窗口关闭、破坏、退出分别是一个消息,都由宏来定义 WM_CLOSE 关闭 WM_DESTROY 破坏 WM_QUIT 退出

我们只要让发生时退出就行了

switch(msg) { case WM_CLOSE:case WM_DESTROY:case WM_QUIT:exit(0);break; }

然后放到回调函数中

long long WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { switch(msg) { case WM_CLOSE:case WM_DESTROY:case WM_QUIT:exit(0);break; } return DefWindowProc(hwnd, msg, wp, lp); }

好了 完整代码(直接复制就好)

#include LPCSTR classname = " "; //设置你的窗口类名 LPCSTR caption = " "; //设置你的窗口标题 int x = 0,y = 0; //设置你的窗口位置 int width = 640, height = 480; //设置你的窗口宽高 //回调函数 long long WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { switch(msg) { case WM_CLOSE:case WM_DESTROY:case WM_QUIT: //窗口关闭的消息 exit(0); break; } return DefWindowProc(hwnd, msg, wp, lp); //定义回调函数的返回值 } int WINAPI WinMain(HINSTANCE hInst, //实例句柄 HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSA wc; //窗口结构体 memset(&wc, 0, sizeof(wc)); wc.lpszClassName = classname; wc.hInstance = hInst; //实例句柄 wc.lpfnWndProc = WndProc; RegisterClassA(&wc); //注册 HWND hwnd = CreateWindowA(classname, caption, WS_VISIBLE|WS_OVERLAPPEDWINDOW, x, y, width, height, NULL, NULL, hInst, NULL); //创建窗口 if(hwnd == NULL) return -1; MSG msg; //消息类 while(true) if(GetMessage(&msg, NULL, 0, 0)) //消息循环 获得消息 { TranslateMessage(&msg); //处理消息 DispatchMessageA(&msg); //分发消息 } }

感谢观看。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3