窗口创建的基本步骤是:

  1. 设计窗口类
  2. 注册窗口类
  3. 创建窗口
  4. 显示更新窗口
  5. 消息循环
  6. 编写回调函数

    ——————————帅气的分割线—————————–
    下面我们一步一步进行讲解:

1.设计窗口类WNDCLASS

我们查看MSDN可以知道窗口类的成员变量有哪些:

typedef struct _WNDCLASS { UINT       style; WNDPROC    lpfnWndProc; int        cbClsExtra; int        cbWndExtra; HINSTANCE  hInstance; HICON      hIcon; HCURSOR    hCursor; HBRUSH     hbrBackground; LPCTSTR    lpszMenuName; LPCTSTR    lpszClassName;
} WNDCLASS, *PWNDCLASS; 

微软为我们设计好了窗口类,我们只需要按照我们的需求填写其中的值就可以了。

  • 我们先看窗口类的第一个字段UINT style;

这个字段是指明窗口的类型风格,其值是可选项,以”CS_“开头,查看MSDN可以知道它所有的可选项,在这里我说两个选项:”CS_HREDRAW“、”CS_VREDRAW“,分别是水平重绘和竖直重绘,表示窗口在水平和竖直方向大小发生变化时会发出WM_PAINT消息来进行窗口的重新绘制。

  • 接下来看第二个字段:WNDPROC lpfnWndProc;

这是窗口的回调函数,这里赋值一个函数的名字(函数指针),这个回调函数的参数有一定的要求,查看MSDN可以知道回调函数的声明如下:

LRESULT CALLBACK WindowProc(  HWND hwnd,      // handle to windowUINT uMsg,      // message identifierWPARAM wParam,  // first message parameterLPARAM lParam   // second message parameter);

这里对回调函数进行一个简单的说明,操作系统(OS)可以捕获程序的消息,并将消息放到该进程的消息队列中,但是OS并不会对这个消息进行处理,如果想要对消息处理就需要程序员自己来写消息响应函数。当用户按下键盘的时候,OS会捕获两个消息WM_KETYDOWN、WM_KEYUP消息,通过TranslateMessage函数将键盘按下和弹起的消息转换成一个WM_CHAR消息,并将按下的按键的ASCII码存放到消息结构体MSG的附加参数中,然后使用DespatchMessage函数将这个消息传递到回调函数中,并由回调函数进行处理。

  • int cbClsExtra;
  • int cbWndExtra;

两个附加参数,给0就行

  • 接下来是字段:HINSTANCE hInstance;

它表示一个应用程序的实例句柄,至于应用程序的实例,可以理解为是一个进程,一个执行的程序。这个字段的值是直接从WinMain函数给过来的。

  • HICON hIcon;
  • HCURSOR hCursor;
  • HBRUSH hbrBackground;

这三个字段分别是窗口的图标、光标、背景。如果要设置窗口的图标要使用函数:

HICON LoadIcon(  HINSTANCE hInstance, // handle to application instanceLPCTSTR lpIconName   // name string or resource identifier);

其中,如果想使用系统自带的图标,第一个参数必须写NULL,第二个参数可以是”IDI_“开头的任意可选项。
而光标一样,需要使用函数:

HCURSOR LoadCursor(  HINSTANCE hInstance,  // handle to application instanceLPCTSTR lpCursorName  // name or resource identifier);

但是对于背景来说,需要使用下面这个函数来设置:

HGDIOBJ GetStockObject(  int fnObject   // stock object type
);

其中fnObject为可选项,详情可查看MSDN

  • LPCTSTR lpszMenuName;
  • LPCTSTR lpszClassName;

下面是最后的两个字段,其中第一个是菜单的名字,第二个是窗口类的名字。由于没有菜单,菜单名设置为空,窗口类名要在CreateWindow时使用。
以上就设计好了窗口类了。

——————–我是华丽的分割线————————–

2. 注册窗口类

使用一下函数就可以,参数是窗口类对象的指针。
ATOM RegisterClass( CONST WNDCLASS *lpWndClass // class data);

3. 创建窗口

使用CreateWindow函数来创建窗口:

  HWND CreateWindow(  LPCTSTR lpClassName,  // registered class nameLPCTSTR lpWindowName, // window name  DWORD dwStyle,        // window styleint x,                // horizontal position of windowint y,                // vertical position of windowint nWidth,           // window widthint nHeight,          // window heightHWND hWndParent,      // handle to parent or owner windowHMENU hMenu,          // menu handle or child identifierHINSTANCE hInstance,  // handle to application instanceLPVOID lpParam        // window-creation data);

其中第一个参数”LPCTSTR lpClassName“就是 刚才在第一步设置窗口类时所起的类名字,第二个参数是该窗口的标题,后面的四个参数是窗口左上角的坐标和宽高,接下来两个参数”hWndParent“、”hMenu“是窗口的父窗口句柄和菜单句柄,由于没有就填NULL,最后一个参数”lpParam“是附加参数填NULL。

4. 显示更新窗口

ShowWindow(hWnd, SW_SHOWNORMAL); //正常显示窗口
UpdateWindow(hWnd); //更新窗口

5. 消息循环

OS每次从该进程的消息队列中取出第一条消息,使用函数如下:

BOOL GetMessage(  LPMSG lpMsg,         // message informationHWND hWnd,           // handle to windowUINT wMsgFilterMin,  // first message  UINT wMsgFilterMax   // last message);

在取消息之前,需要声明一个MSG结构的消息变量,它不需要初始化,直接传入第一个参数,该函数会将取出的消息填入该变量。第二个参数是窗口句柄,表明你要接收那个窗口的消息,如果想接收该进程的所有消息,该参数填写NULL。第三、四个参数是消息过滤的最小最大值,表明你要接受消息的范围,如果接收全部消息,这两个值填0就行。

这个GetMessage有一个BOOL型的返回值,如果取到的消息是WM_DESTROY消息则返回假,所以我们将这个函数放到while循环中,只要有消息就执行循环体,直到用户关闭窗口时发出WM_DESTROY消息后while循环条件为假退出。

在循环体中,我们要处理消息,使用以下两个函数:

TranslateMessage(&msg); //翻译消息
DispatchMessageA(&msg); //将消息传入窗口的回调函数

这两个函数上面说到过,这里不进行赘述。

6. 编写回调函数

由于在第五步的时候使用DispatchMessage函数将一个消息传入回调函数,则在回调函数中对参数msg进行判断和进一步处理。

再次特别说明两个消息:”WM_CLOSE“、“WM_DESTROY”
当用户点击关闭窗口按钮的时候会发出一个WM_CLOSE消息,我们进行窗口的销毁,但是一定要注意此时只是销毁了窗口,程序仍然在后台执行。销毁窗口的函数DestroyWindow又会发出一个WM_DESTROY的消息,在处理这个消息的时候使用PostQuitMessage这才真正的退出程序。

对于我们没有处理的其他消息,我们不能对其不管,所以我们对其他不感兴趣的消息调用系统默认的回调函数DefWindowProc

———————–这是另一条分割线————————
下面是程序的结果:

上图为程序运行后的界面


点击鼠标左键后窗口显示文字


按下键盘按键后窗口弹出对话框


点击退出按钮窗口弹出对话框,点击是程序结束

———————–帅气的分割线—————————–
下面就是程序的源代码:

#include <Windows.h>
#include <stdio.h>/*
* 窗口的回调函数
*/
LRESULT CALLBACK WindowProc(HWND hwnd,      // handle to windowUINT uMsg,      // message identifierWPARAM wParam,  // first message parameterLPARAM lParam)   // second message parameter
{HDC hDC;PAINTSTRUCT ps;switch (uMsg){case WM_PAINT:/** 窗口重绘时调用* 只有在WM_PAINT消息中才可以使用BeginPaint、EndPaint* 其他消息使用GetDC、ReleaseDC*/hDC = BeginPaint(hwnd, &ps);TextOut(hDC, 0, 50, "这是在WM_PAINT消息中重绘的文字", strlen("这是在WM_PAINT消息中重绘的文字"));EndPaint(hwnd, &ps);break;case WM_CHAR:MessageBox(hwnd, "WM_CHAR消息触发了", "提示", MB_OK);break;  case WM_LBUTTONDOWN:hDC = GetDC(hwnd);TextOut(hDC, 0, 70, "这是在WM_LBUTTONDOWN消息中重绘的文字", strlen("这是在WM_LBUTTONDOWN消息中重绘的文字"));ReleaseDC(hwnd, hDC);break;case WM_CLOSE:if (IDYES == MessageBox(hwnd, "确定要退出吗?", "提示", MB_YESNO)){//确定退出,销毁窗口,抛出一个WM_DESTYRY的消息DestroyWindow(hwnd); }break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, uMsg, wParam, lParam);}return 0;
}int WINAPI WinMain(HINSTANCE hInstance,      // handle to current instanceHINSTANCE hPrevInstance,  // handle to previous instanceLPSTR lpCmdLine,          // command lineint nCmdShow)              // show state
{//第一步、设计窗口类WNDCLASS wndclass;wndclass.style = CS_HREDRAW | CS_VREDRAW; //设置水平竖直重绘,发送WM_PAINT消息wndclass.lpfnWndProc = WindowProc; //指定窗口的回调函数wndclass.cbClsExtra = 0;wndclass.cbWndExtra = 0; //两个额外数据wndclass.hInstance = hInstance;wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);wndclass.hCursor = LoadCursor(NULL, IDC_CROSS);wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);wndclass.lpszMenuName = NULL;wndclass.lpszClassName = "myWindowClass";//第二步、注册窗口类RegisterClass(&wndclass);//第三步、创建窗口HWND hWnd = CreateWindow("myWindowClass",    //窗口类的名字"my first window",  //窗口标题WS_OVERLAPPEDWINDOW,    //样式0, 0, 500, 500, //左上角坐标,宽高NULL, //父窗口NULL, //菜单hInstance, //实例NULL); //附加参数//第四部、显示更新窗口ShowWindow(hWnd, SW_SHOWNORMAL); //正常显示窗口UpdateWindow(hWnd); //更新窗口//第五步、消息循环MSG msg;while (GetMessageA(&msg, NULL, 0, 0)){TranslateMessage(&msg); //翻译消息DispatchMessageA(&msg); //将消息传入窗口的回调函数}return 0;
}

Windows编程-创建窗口相关推荐

  1. 通过Windows API 创建窗口的过程理解windows消息机制

    一个基于windows API 的基于窗体.消息循环.事件驱动的 Windows C语言风格的Windows 程序. 创建一个Win32应用程序的步骤: 1.定义 WinMain 函数: 2.设计窗口 ...

  2. C/C++:Windows编程—创建进程、终止进程、枚举进程、枚举线程、枚举DLL

    创建进程的2种方式 1. 创建进程最简单的方法 UINT WINAPI WinExec(_In_ LPCSTR lpCmdLine, // 指向可执行文件_In_ UINT uCmdShow // 程 ...

  3. C语言windows编程编写窗口

    突然想做一个透明的windows窗口置顶,可以放一些信息上去,这样查阅资料方便.就像音乐播放器的歌词一样.慢慢学吧,第一步先学会做窗口. 参考: https://brothergrup.iteye.c ...

  4. Windows编程 第四回 Windows程序的生与死(下)

    致歉 很抱歉,读者看到的这篇文章将是我写的最没什么条理的一篇了,由于这一块儿内容是所有Windows程序的核心与基础,所以我分了三回来写.我想讲 得既易懂有又丰富,无奈本人才疏学浅,每每一提笔就要查很 ...

  5. Qt:Windows编程—Qt实现进程管理

    前言 继续学window编程,学呀学呀 学无止境,学到Windows进程相关API了.利用相关的API使用Qt写界面实现了一个简单的进程管理.主要用到 进程的创建.进程的枚举.线程的枚举.DLL的枚举 ...

  6. Windows编程 Windows程序的生与死(下)

    再谈程序之"死" 记得在第二回中我对程序的"死"只是一句话带过,因为我还没有铺垫好,好了现在我们可以详细的分析一下这个过程了. 这还要从while消息循环说起, ...

  7. 【Windows编程】windows窗口创建过程详解

    文章目录 前言 1 应用程序的分类 2 应用程序分类的对比 3 编译工具 4 windows库文件和头文件 5 WinMain函数和MessageBox函数初始 6 窗口类 7 窗口类的分类 8 注册 ...

  8. Windows编程---使用C/C++语言创建一个窗口

    序言 记得刚学习C语言的时候,我还只能写出在"小黑框"里面运行的控制台程序.后来我了解到这种控制台程序属于命令行界面(CLI,Command-Line Interface),而我们 ...

  9. 【免杀前置课——Windows编程】五、窗口控件——什么是控件、Windolws 窗口两大类、Windows标准控件/通用控件、控件响应的接收、创建窗口制作不同控件

    窗口控件 WINDOW控件 什么是控件? 控件是常见的窗口上的交互元素.例如:一个按钮,一个复选框,一个列表框等.当控件的特定功能被触发后,会主动发送消息通知父窗口,父窗口可以通过发送消息给控件控制控 ...

最新文章

  1. 德鲁克管理思想:管理的7大理论、43条原则,每一条都是精华
  2. 不讲武德,拿到户口后立马辞职...
  3. 为什么是错的?????
  4. linux 链接 文件,聊聊 Linux 里的文件链接
  5. SQL语句错误:Operand should contain 1 column(s)【查询多个字段不用加括号】
  6. 2005年度国产空间信息系统软件测评工作圆满结束
  7. android selector点击修改颜色,Android Selector 按下修改背景和文本颜色的实现代码
  8. 雷霆战机源代码c语言,C++实现雷霆战机可视化小游戏
  9. sql \n 查询_探索SQL查询提示选项(快速N)
  10. ssas报表项目数据集_处理SSAS多维OLAP多维数据集的有效方法
  11. 读过的书,记录一下,不要忘记提高自己
  12. 深入思考内积运算,再看傅里叶系数、伽辽金法本质
  13. Redis 连接命令
  14. easyar android 开发,EasyAR 使用Unity如何导出android项目
  15. 2022-2027年中国OLED发光和传输材料市场规模现状及投资规划建议报告
  16. 智能车基于RT1064+无线串口透传模块利用MATLAB辅助调节PID参数
  17. 第一节计算机课学什么,第一节电脑课作文
  18. Linux diff命令详解
  19. 手把手教你如何结合腾讯云开发微信小程序
  20. 一行代码解决vue数据量大卡顿问题

热门文章

  1. C# 开发企业内部微应用接入钉钉获取用户信息
  2. NOIP 2004 合唱队形
  3. 消息称光宇华夏管理层调整 CEO高苏华萌生退意
  4. 《电路/电路原理》—戴维宁(南)定理实战演练
  5. linux实践感悟与体会100字,掌上综素b5学科时间活动心得体会50字
  6. 使用AI制作 3d 模型初学者指南,如何在 Blender 3d 中使用stable diffusion
  7. 绩效考核-项目经理绩效考核指标
  8. 台式计算机除尘方法,一种计算机主机箱除尘装置及其工作方法与流程
  9. 7-1 厘米换算英尺英寸(15 分)
  10. 【学习记录】状语和状语从句