VisualStudio Qt開發環境搭建以及Qt moc的講解

目錄

前言

搭建QT開發環境

準備工作

新建工程

工程配置

代碼實驗

Q_OBJECT

Meta-Object System

MOC (Meta-Object Compiler)

VisualStudio相關設置


前言


最近在使用VisualStudio搭建Qt開發的時候遇到了一些問題,故寫此文章記錄一下解決問題的過程。問題主要有以下幾點:

1.如何在VisualStudio中使用Qt

2.Q_OBJECT引起的編譯失敗

對於問題1,主要是如何正確的搭建QT開發環境了,這裏我沒有使用Qt VisualStudio Tools,具體的配置過程將在下文提到

對於問題2,涉及到Qt的meta-object system,在本文中會幫助大家認識Qt中一個非常重要的工具:MOC

本文的重心在於快速的創建一個工程復現我所遇到的問題,給出我的一些解決方法供大家參考。

 

搭建QT開發環境


準備工作

IDE: VisualStudio 2019

Qt版本:Qt 5.13.0

VisualStudio軟件以及Qt的下載這裏不再詳細介紹,本文使用的Qt版本是開源版本

Qt安裝完成後找到下面的文件目錄:

  • 你的Qt安裝根目錄/5.13.0/msvc2017

比如我的該目錄位於:F:\Qt\5.13.0\msvc2017

我們把這個路徑命名爲QTDIR,記住這個路徑後面會用到。

新建工程

我這裏新建了一個空項目Project2,爲其創建main.cpp

並添加如下代碼:

#include <iostream>
int main(int argc, char* argv[]) {
	return 0;
}

這是一個空的主函數,爲了能夠使用Qt的各種類,我們需要把Qt的代碼庫包含到項目中來。

工程配置

我們要在VisualStudio中創建一個用戶宏,以方便我們添加對Qt代碼庫的引用

  • 打開屬性管理器(View->Other Windows->Property Manager)
  • 雙擊Microsoft.Cpp.Win32.user,選擇AddMacro,創建一個名爲QTDIR的宏,然後把上文中的QTDIR路徑添加上去,點擊確定即可,如下圖所示:
  • 這麼搞有一個好處是,以後新建的項目都可以使用這個宏,不用每次重複創建了,一勞永逸。

接下來把Qt的include目錄包含到項目中

  • 打開解決方案瀏覽器(Solution Explorer),右鍵單擊項目名稱,單擊Properties打開屬性設置面板
  • 選擇C/C++->General,編輯Additional Include Directories,添加如下目錄:
    • $(QTDIR)\include;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtWidgets
  • 添加鏈接庫
    • 同樣在屬性設置界面,打開Linker->General 編輯Additional Library Directories, 添加如下目錄
      • $(QTDIR)\lib
    • 打開Linker->Input, 編輯Additional Dependencies,添加我們所需要用到的靜態鏈接庫
      • qtmain.lib;Qt5Core.lib;Qt5Widgets.lib;Qt5Gui.lib;

代碼實驗

按照上面的步驟配置完成後,我們可以迴歸我們的代碼,可以嘗試添加一些Qt的內容:

#include <iostream>
#include <QApplication>

int main(int argc, char* argv[]) {
	QApplication a(argc, argv);
	return a.exec();
}

編譯通過,運行時報如下錯誤:

彈出缺少一系列dll,不要慌張,我們到qt的bin目錄裏,找到這些dll,把它放到我們的編譯輸出的Debug目錄下就行了,例如本文中在如下位置F:\Qt\5.13.0\msvc2017\bin)

拷貝過去後再次編譯運行則不再報錯。

到了這裏我們似乎已經可以開始Qt的開發了,嘗試着創建一個窗口來,我們新建一個類,然後繼承自QMainWindow

#pragma once
#include <QMainWindow>
class MyWindow :
	public QMainWindow
{
public:
	MyWindow(QWidget* parent = 0, Qt::WindowFlags flags = 0);
	~MyWindow();
};

接下來在main.cpp中顯示該窗口

#include <iostream>
#include <QApplication>
#include "MyWindow.h"

int main(int argc, char* argv[]) {
	QApplication a(argc, argv);
	MyWindow w;
	w.show();
	return a.exec();
}

編譯運行,發現確實創建了一個小窗口

走到這一步似乎我們搭建Qt開發環境的任務就大功告成了,但我們似乎遺漏了一點:在使用QtCreator進行開發時,創建出來的窗體類中都包含了一個叫Q_OBJECT的宏,我們乾脆也把這個宏加上好了,這樣顯得更完整了:

#pragma once
#include <QMainWindow>
class MyWindow :
	public QMainWindow
{
	Q_OBJECT
public:
	MyWindow(QWidget* parent = 0, Qt::WindowFlags flags = 0);
	~MyWindow();
};

再次編譯,報錯

爲什麼會報錯呢,代碼看上去並沒有問題,要明白爲什麼報錯還是需要對Q_OBJECT宏有一個更深入的認識

 

Q_OBJECT


我們知道在使用QtCreater創建的窗體頭文件中都會被標上Q_OBJECT這樣一個宏定義,對於剛接觸Qt的開發者可能會感覺很奇怪,爲啥頭文件裏都要加一個這玩意兒,不加不行麼?

我們先看一下官方的說明:

The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt’s meta-object system

大概意思就是如果你要在類中聲明信號/槽或者使用到了一些Qt meta-object系統提供的某些服務的時候你就得在這個類頭文件的私有域添加Q_OBJECT宏,換言之,如果你不打算使用信號/槽或meta-object相關服務的時候,不加這個宏也是可以的

就比如上面提到的例子,沒有添加Q_OBJECT依然不妨礙代碼的正常編譯和窗口的生成。

(當然最好是不管用不用得到信號和槽,都把Q_OBJECT加上,雖然可能會增加一點點編譯時間)。

在官方文檔中對信號和槽的說明中,也提到了所有包含signals或slots的類都必須在他們聲明的最頂部寫上Q_OBJECT,而且這些類必須繼承自QObject

我們在代碼中使用這個宏,就是爲了能夠使用信號/槽這種機制,那麼Qt是如何處理Q_OBJECT的呢?答案就是:moc,在介紹moc之前我們先介紹一下Qt的meta-object system

 

 

 

Meta-Object System


在前文中提及了QT的meta-object system,meta-object system包含了信號/槽的通信機制,運行時類型信息以及動態屬性。

meta-object system建立在另外三種東西之上,分別爲:

  1. QObject,爲對象提供了一種基類,使之能夠利用到meta-object system
  2. Q_OBJECT,在類聲明的私有域中添加Q_OBJECT宏可以讓該類能夠使用到meta-object system的特性,比如動態屬性和信號槽
  3. MOC(meta-object compiler),爲每一個QObject的子類創建必要的代碼以便其使用meta-object system的特性

 

MOC (Meta-Object Compiler)


認識了Qt的meta-object system之後,我們着眼看一下MOC。MOC是一個工具,它的exe文件可以在QTDIR\bin下面找到。

它做了哪些事情呢?moc會讀取一個c++源文件,moc會檢查該文件中定義的類聲明中是否包含Q_OBJECT宏,如果包含的話,就會爲其生成一份cpp源文件,並在該文件中處理Q_OBJECT的實現。我們需要把這個新生成的源文件同樣包含進項目中參與編譯才行。

下面我們可以具體操作一下:

  1. 進入Qt的bin目錄下,在該目錄下調出命令行
  2. 輸入moc "yourfilename.h" –o "moc_yourfilename.cpp", 需要注意的是由於此處是在Qt的bin目錄下開啓的命令行,所以在輸入文件名和輸出文件名的時候還要寫全文件的路徑
  3. 按下回車,然後到輸出目錄查看,可以找到生成的moc開頭的cpp文件

我們到VisualStudio中把該moc開頭的源文件包含進去,再次編譯,不再報錯。

上面的例子使用命令行窗口調用moc來生成Q_OBJECT所需要的額外實現代碼,顯得有點麻煩,這裏介紹一下如何在VisualStudio進行一些配置來減少我們的工作量

 

VisualStudio相關設置


對於那些繼承自QObject且代碼中使用到Q_OBJECT宏的類,我們可以右鍵其頭文件,單擊Properties,打開屬性界面

將ItemType改爲Custom Build Tool

單擊 “應用”,此時左側會刷新出來CustomBuildTool的配置選項,

選中CustomBuildTool,在Command Line中填入:

"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp"

在Outputs中填入:

.\GeneratedFiles\$(Configuration)\moc_%(Filename).cpp

這樣當我們第一次編譯的時候,VS就會調用moc並在我們指定的目錄下生成一系列meta-object code

我們在只需要把這些生成的代碼include到我們的項目中再次編譯就不會報錯了

上面的配置中會把生成的代碼放到GeneratedFiles文件夾裏

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章