Windows编程_Lesson004_项目预备_重新认识MFC

2024-06-06 12:18

本文主要是介绍Windows编程_Lesson004_项目预备_重新认识MFC,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

MFC本质

MFC本质上就是一套开发框架,它可以帮助我们快速开发。MFC是以类的方式重新将Windows API进行了归类,MFC层次结构图链接。一提到类,相信对于了解C++或者其它比较高级一点的开发语言的同学肯定就不会感到那么恐惧MFC了。MFC既然是一套,所以你就不一定非得在VS环境下编译,它可以在任何支持C++的编译器下面进行编译,但是这些编译器必须是在Windows下的,因为它所使用的大多数API都是Windows下的,和Linux或者Unix是不兼容的。虽然说可以在任何编译器下进行编译MFC这套框架,但是我们还是最好在VS下面进行MFC的编译和开发,因为VS对MFC的支持是最好的。
下面是MFC层次结构图,看到这些图,我们对MFC是不是了解更加清晰了呢?
它就是一层一层的继承,和C++的继承是一模一样的。
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
上面所述的目的就是我们(主要是刚接触MFC的同学)不要觉得MFC有多难多复杂,它其实就是一个一个的类,一步一步的看这个类是从哪儿继承过来的,然后我们就知道这个类中都有什么函数(接口)可供我们使用了,用到什么函数,直接就去这个类里面查找就OK了!这么一解释,MFC是不是变得不是那么难了呢?

Dialog创建过程

XXX代表的数创建的对话框工程的名字。
MFC的对话框创建完成后,存放代码的有两个类,一个是XXXApp的类,另一个是XXXDlg的类。我们需要注意一下几个点:

第一个点,在XXXApp类中,有这样的一个虚函数:

virtual BOOL InitInstance();

这个函数在程序启动的时候被被动的调用。

第二个点,在XXXDlg类中,有这样的一个函数:

BOOL OnInitDialog() override;

注意:所有的OnXXX函数,代表的意思都是被被动的调用,意思就是当发生某些消息的时候就会调用OnXXX函数!

特别需要注意的是:
XXXDlg类是完成界面功能的,而XXXApp类是主要实现程序逻辑的功能的。
在MFC这套框架中,程序和窗口是分开的。窗口只是响应一些界面的消息,它一定不是来完成逻辑的,XXXApp才是来完成逻辑的。

详细的执行过程是这样的,XXXApp类会生成唯一的一个全局对象theApp,这个theApp会执行它的InitInstance()函数,而 InitInstance()函数里面会生成XXXDlg类的对象dlg,dlg调用它的函数DoModal(),DoModal()再调用BOOL OnInitDialog() override,此时,一个对话框界面就活生生的展现在我们的面前了,我们可以在对话框界面上做一些事情,当这个对话框关闭的时候,它也会返回一个值,我们可以根据返回值,也可以做一些相应的收尾工作。

这里写图片描述

这就是MFC的对话框创建和销毁的全部过程,是不是很简单呢?

对话框的使用

这里写图片描述

这里写图片描述

这里写图片描述
如果按照上面进行添加对话框标题,会弹出下面的错误
这里写图片描述

当我们单步调试,进入SetWindowText函数,如下图所示:
这里写图片描述
我们可以看到hWnd是一个空指针,所以就会出现崩溃。那么有的同学就会产生疑问,我们的对话框对象不是已经创建出来了吗?那么为什么不能调用SetWindowText函数呢?这是因为SetWindowText函数是针对于窗口来进行操作的,而窗口是属于内核对象,也就是意味着,有没有类,跟我内核对象是一点关系都没有的,也就是说,只要你有窗口,我就能做窗口相关的事情。
总的来说就是对话框对象是我们自己程序的对象,我们的程序对象维护了一个窗口内核对象,注意:我们只是维护一个窗口内核对象,它是不属于我们自己程序的,应该说,所有的内核对象都是不属于程序的,它们是属于操作系统的,我们能做的是,我们需要什么,操作系统帮我们拿出来我们需要的东西,然后在确保拿过来这个东西的时候,我们再对它们进行相关操作。,所以我们当前的对话框对象并没有拿到内核对象,因为必须在DoModal之后,才能拿到窗口内核对象,也就是说,DoModal函数里面才能拿到窗口内核对象。
我们的对话框类严格来说是一个窗口管理类,我们的窗口是一个内核对象,而窗口内核对象是通过操作系统来分配的,所以我们的窗口管理类唯一能做的是向操作系统要一个窗口内核对象(起到一个通知的作用),然后再让这些窗口对象做一些相应的改变,比如通过SetWindowText函数来修改对话框标题等。
这里写图片描述

那么问题又来了,SetWindowText函数只能在DoModal函数之后才能起作用,但是DoModal函数是一个阻塞函数,SetWindowText函数是不能被执行到的呀!!!这该怎么办呢?如果我们使用的是非模态对话框,那么在Create函数之后,是可以进行SetWindowText函数来修改标题的。
那么对于模态对话框,我们就没有办法解决这个问题了吗?办法是有的,比如我们可以对DoMoDal函数进行改造。我们可以想象一下DoModal函数里面做的事情:

可定CreateWindow -> 发送WM_CREATE消息 -> OnInitialDialog函数里面可以做初始化操作

所以我们可以重写OnInitialDialog函数,在OnInitialDialog函数中,我们首先可以调用父类里面的CDialogEx::OnInitialDialog函数,然后再做窗口设置操作,调用SetWindowText函数,来更改对话框标题,重写的OnInitialDialog函数如下所示:

这里写图片描述

此时,我们再看一下执行效果:

这里写图片描述

我们只重写OnInitialDialog函数,就解决了程序崩溃的问题,原来的调用没有任何一点儿改变:
这里写图片描述

从上面的例子可以看出,MFC实际上是以C++的方式对Windows里面的很多特性进行了一层一层的封装,然后对Windows中的每一个消息都相应的产生一个On…的函数,所以我们可以利用C++里面的特性,来对MFC进行各种各样的填充、扩充以及修改。

我们如果想正儿八经使用MFC这套框架的话,把MFC写的与众不同一些的话,我们更多的是对MFC的类进行继承,然后对特定的消息进行特定的操作。

下面介绍三种方式来定制MFC

1. 构造函数接收参数修改对话框风格的例子
2. 重载一个接收参数的DoModal函数
3. 设置一个方法

1. 构造函数接收参数例子
增加一个带参数的构造函数
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

上面的方式虽然可以,但是并不推荐。我们应该使用一个enum来枚举一些对话框风格
这里写图片描述

这里写图片描述

这里写图片描述

2. 重载接收参数的DoModal函数修改对话框风格的例子

这里写图片描述

这里写图片描述

3.设置一个方法改对话框风格的例子就不再举例子了

DoModal函数的返回值

当我们点击对话框上面的×号关闭对话框时,DoModal函数会返回2,它代表是IDCANCEL消息,然后就将对话框关闭掉了,如果我们想使用自己的按钮来关闭对话框,该如何实现呢?
那么这样实现我们的关闭按钮函数,可以将对话框关闭掉吗?

这里写图片描述

我们也不知道OnClose函数里面到底做了什么事情,调试一下!!!

这里写图片描述
这里写图片描述
这里写图片描述
从上面可以看出OnClose函数什么事情都没有做,所以这个按钮是不能将对话框关闭掉的。

如果我们调用父类的OnClose函数,效果会怎样呢?

这里写图片描述
通过调试,可以看出,跟调用本类中的OnClose函数是一模一样的。

那么我们该如何才能自己将对话框关闭呢?很简单,自己重载一个OnClose函数,让OnClose函数调用CloseWindow函数,就可以将对话框关闭。
这里写图片描述
这里写图片描述

MFC的按钮约定俗成的一些按钮。
这里写图片描述

我们还可以使用EndDialog函数,根据传入的不同的参数,来决定DoModal函数的返回值。
这里写图片描述
这里写图片描述
从上面可以看出,如果我们传入的是IDCANCEL,那么DoModal函数的返回值就是2了。

这篇关于Windows编程_Lesson004_项目预备_重新认识MFC的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1036083

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

Windows设置nginx启动端口的方法

《Windows设置nginx启动端口的方法》在服务器配置与开发过程中,nginx作为一款高效的HTTP和反向代理服务器,被广泛应用,而在Windows系统中,合理设置nginx的启动端口,是确保其正... 目录一、为什么要设置 nginx 启动端口二、设置步骤三、常见问题及解决一、为什么要设置 nginx

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同

在 Windows 上安装 DeepSeek 的完整指南(最新推荐)

《在Windows上安装DeepSeek的完整指南(最新推荐)》在Windows上安装DeepSeek的完整指南,包括下载和安装Ollama、下载DeepSeekRXNUMX模型、运行Deep... 目录在www.chinasem.cn Windows 上安装 DeepSeek 的完整指南步骤 1:下载并安装

IDEA运行spring项目时,控制台未出现的解决方案

《IDEA运行spring项目时,控制台未出现的解决方案》文章总结了在使用IDEA运行代码时,控制台未出现的问题和解决方案,问题可能是由于点击图标或重启IDEA后控制台仍未显示,解决方案提供了解决方法... 目录问题分析解决方案总结问题js使用IDEA,点击运行按钮,运行结束,但控制台未出现http://

解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题

《解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题》文章详细描述了在使用lombok的@Data注解标注实体类时遇到编译无误但运行时报错的问题,分析... 目录问题分析问题解决方案步骤一步骤二步骤三总结问题使用lombok注解@Data标注实体类,编译时

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下