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的註釋裡面可以看到,如何使用它

/*!
    Creates an instance of QApplication, passing the command line of
    \a mfcApp to the QApplication constructor, and returns the new
    object. The returned object must be destroyed by the caller.

    Use this static function if you want to perform additional
    initializations after creating the application object, or if you
    want to create Qt GUI elements in the InitInstance()
    reimplementation of CWinApp:

    \code
    BOOL MyMfcApp::InitInstance()
    {
    // standard MFC initialization
    // ...

    // This sets the global qApp pointer
    QMfcApp::instance(this);

    // Qt GUI initialization
    }

    BOOL MyMfcApp::Run()
    {
    int result = QMfcApp::run(this);
    delete qApp;
    return result;
    }
    \endcode

    \sa run()
*/

首先在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_OBJECT
public:
	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窗口退出時,關閉QApplication
setQuitOnLastWindowClosed(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_OBJECT
public:
	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開發界面的實現步驟的文章就介紹到這瞭,更多相關MFC QT開發界面內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: