MFC程序中使用QT开发界面的实现步骤是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
如果你有一个现成的MFC项目在做维护,但是你厌倦了使用MFC繁琐的操作来做界面美化,或者你需要在这个项目中用到QT里面好用的某些功能;亦或者是你需要使用某些只能在MFC中使用的组件,但是界面这部分已经用QT做好了。那么这篇文章可能可以帮助到你
演示环境使用Visual Studio 2019 + QT5.12.8 版本
添加QT依赖
首先创建一个基于对话框的MFC工程,当然其他的像是多文档、单文档工程也是可以的,只是为了简单起见我这里用的是对话框
然后通过鼠标右键点击项目,然后依次点击属性 --> C/C++ -->常规在工程的附加头文件中添加上QCore、QGui、QWidget和QT的头文件路径
这里记得按照对应编译选项来选择包含64位或者32。
接着在连接器–>常规 中的附加库目录中添加qt的lib库
最后再在连接器–>输入中添加依赖的lib文件,需要注意的是,debug版本需要链接上带d的lib文件,release则链接上不带d的。
先编译一下,如果没有问题,qt相关的配置已经完成了
添加信号槽机制
MFC是基于Windows 消息队列来处理和响应ui事件的,而qt是采用信号槽机制来响应的,我们虽然添加了qt的依赖,但是现在只能使用其他的qt库,无法使用qt中的信号槽,需要额外添加一些组件来使mfc支持信号槽。
好在这部分需求qt相关的研发人员已经考虑到了,可以在github中找到 QMfcApp
我们可以将这两个文件给拷贝下来,添加到项目中。并且在cpp文件相应位置添加上 #include "pch.h"
包含预处理头
中间会有报错,这是因为在Unicode 字符集下 CString 中的字符串类型是 wchar_t*
QString::fromLocal8bit 无法 从 wchar_t*
转化为 char*
所以这里可以修改一下,使用 QString::fromStdWString()
,然后进行编译
在QMfcApp.cpp的注释里面可以看到,如何使用它
首先在app类的InitInstance 函数中初始化QApplication类
BOOL CMFCWithQtApp::InitInstance(){CWinApp::InitInstance();QMfcApp::instance(this);return true;}
然后需要重写 app类的run 方法,在该方法中调用QMFC 的run方法
int CMFCWithQtApp::Run(){int result = QMfcApp::run(this);delete qApp;return result;}
再次编译一下,完成了往mfc中添加信号槽机制的功能
添加qt界面
在项目中新建一个界面类,让他继承自QWidget,如下
// MainUI.h#pragma once#include <QWidget>class MainUI: public QWidget{Q_OBJECTpublic:MainUI(QWidget* parent = nullptr);~MainUI();};//MainUI.cpp#include "pch.h"#include "MainUI.h"#include <QPushButton>MainUI::MainUI(QWidget* parent) :QWidget(parent){setWindowTitle("Qt Windows");setFixedSize(800, 720);QPushButton* pBtn = new QPushButton(QString::fromLocal8Bit("这是一个Qt按钮"), this);}MainUI::~MainUI(){}
然后在App 类的 InitInstance 中启动该界面
BOOL CMFCWithQtApp::InitInstance(){CWinApp::InitInstance();QMfcApp::instance(this);MainUI ui;ui.show();QMfcApp::exec();return FALSE;}
然后编译,这个时候发现会在链接的时候包一些错误,找不到一些 meta
的函数的定义
配置元编译过程
传统的c/c++ 从源代码到生成可执行文件的过程需要经过预编译、编译、链接。而qt在预编译前会进行元编译,生成一个moc_
开头的源码文件,后续编译的真正的文件其实是这个元编译生成的文件。MFC项目不会经历这一步,所以会报错。
在MainUI.h
上点击右键,选择属性, 将项目类型选择为自定义生成工具
然后应用,这个时候会出现新的选项
在命令行和输入这两栏中分别填入 "moc.exe" "%(FullPath)" -o ".\GeneratedFiles\moc_%(Filename).cpp" "-fpch.h" "-f../MainUI.h"
和 .\GeneratedFiles\moc_%(Filename).cpp
命令行的含义是会使用moc元编译器编译当前文件,并将生成的文件放入到当前目录下的GeneratedFiles子目录中,并且以moc_开头作为文件名,后面 -f
表示生成的新文件中会包含 #include "pch.h"
和 #include "../MainUI.h"
然后在文件中选择右键,编译。这样将会生成moc文件(两边的双引号也好包含进去)
如果编译的时候报找不到moc.exe 这样的错误,请配置QT中的bin路径到环境变量中
我们将新生成的文件添加到项目中
再次编译,成功过后点击运行就可以看到qt界面已经展示出来了
一些问题的处理
窗口出来了,但是在我的环境下出现两个问题,关闭窗口后进程无法退出;程序退出后出现内存泄露的问题
针对这两个问题可以在QMfcApp.cpp 文件中修改
// 表示在最后一个qt窗口退出时,关闭QApplicationsetQuitOnLastWindowClosed(true); //将之前的false改为true
// ~QMfcApp() 中添加这两句,当析构完成后关闭进程HANDLE hself = GetCurrentProcess();TerminateProcess(hself, 0);
测试信号槽
我们可以在MainUI中添加信号槽
MainUI::MainUI(QWidget* parent) :QWidget(parent){setWindowTitle("Qt Windows");setFixedSize(800, 720);QPushButton* pBtn = new QPushButton(QString::fromLocal8Bit("这是一个Qt按钮"), this);connect(pBtn, &QPushButton::clicked, [=]() {QMessageBox::information(this, QString::fromLocal8Bit("信号槽"), QString::fromLocal8Bit("这是由信号槽弹出来的"));});}
点击按钮之后,消息框也正常弹出来了
使用qt designer 设计界面
使用 qtdesigner 设计这样一个界面
qtdesigner 会生成一个.ui
文件,在qt的开发环境中,会自动使用uic.exe
将这个文件生成一个对应的.h文件。我们先将ui文件导入到项目,并且按照之前的步骤设置自定义生成工具,填入如下命令行
"uic.exe" "%(FullPath)" -o ".\ui_%(Filename).h"
并且填写上输出路径.\ui_%(Filename).h
编译之后会生成一个对应的ui_MainUi.h
文件,修改对应的MainUI.h
头文件,加上关于它的引用,并且添加一个ui的对象指针
//MainUI.h#pragma once#include <QWidget>#include "ui_Main.h"class MainUI: public QWidget{Q_OBJECTpublic:MainUI(QWidget* parent = nullptr);~MainUI();private:Ui::mainUI* m_pUI;};
在类的构造中,使用ui对象来产生界面元素
//MainUI.cpp#include "pch.h"#include "MainUI.h"#include <QPushButton>#include <QMessageBox>MainUI::MainUI(QWidget* parent) :QWidget(parent),m_pUI(new Ui::mainUI()){m_pUI->setupUi(this);connect(m_pUI->pushButton, &QPushButton::clicked, [=]() {QMessageBox::information(this, QString::fromLocal8Bit("qt 信号槽测试"), m_pUI->lineEdit->text());});}MainUI::~MainUI(){delete m_pUI;}
执行效果如下
看完上述内容,你们掌握MFC程序中使用QT开发界面的实现步骤是什么的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网行业资讯频道,感谢各位的阅读!