您好!歡迎加入Qt MOOC!
本主題涵蓋了您在學習本課程時所需的大部分基本知識。我們將從課程的角度,以練習的形式來討論Qt項目。還會介紹一些重要概念,這些概念將幫助您了解Qt的基礎知識。我們使用Qt的官方文檔作為輔助材料,這會讓您熟悉Qt的官方文檔。另外,我們還將討論構建,qmake和調試信息等。
如果所有這些對您來說都已經很熟悉了,你可以直接去完成練習,然后進入更具體的主題。如果您在完成Hello World練習時不知道發生了什么情況,請回來閱讀基礎知識,我們不會對您有任何偏見!
在開始繁重的工作之前,我們將介紹一些基本概念來幫助您開始。它們是Qt中的全局聲明、模塊和命名空間。
1. 全局聲明和宏
讓我們來討論一下Qt中的全局聲明,您可以在Qt文檔中找到一個完整的全局聲明列表。
全局聲明包括類型、函數和宏。在進入下一章之前,您絕對不需要記住這個列表,但重要的是,您要知道它是什么,可以用它來做什么,因為您可能會發現它在各種場合下都非常有用。在本主題的最后,我們將討論在全局聲明中找到的一些有用的調試函數。
類型定義部分是用于方便基本類型的定義(其中一些類型保證了Qt在所有支持的平臺上的特定位大小),部分是與Qt消息處理相關的類型。這些函數與生成消息、Qt版本處理以及比較和調整對象值有關。最后,一些聲明的宏允許程序員將編譯器或平臺特定的代碼添加到他們的應用程序中,而另一些宏則是用于更大操作的方便宏。
如果有必要,我們會在作業或學習主題中明確地向您介紹全局聲明列表。
2. Qt模塊和命名空間
接下來,讓我們來討論一下Qt中的模塊。這是Qt中的模塊列表。
要將模塊包含到項目中,您需要將它們包含在項目的.pro
文件中。如果使用qmake,則默認情況下將包括Core和GUI模塊。如果您沒有在項目中使用GUI模塊(無論如何,在開始時大部分時間我們都不會使用GUI模塊),只需在您的項目.pro
文件中寫入QT -= GUI
即可將其禁用。所有其他Qt模塊都依賴于Qt Core模塊。
接下來,我們看一下有關命名空間及其在Qt中的用法的一些基本知識。這是Qt中主要命名空間的列表。當然,該課程我們不會使用所有的命名空間,但是在開始之前,我們相信事先了解這個列表會對您有所幫助。
讓我們舉一個包含命名空間的示例!假設您想在代碼中包含QtConcurrent
命名空間。讓我們仔細看看QtConcurrent
的文檔頁面:
要包含QtConcurrent
命名空間,您需要在兩個地方進行具體說明:相關文件的頭文件(#include <QtConcurrent>
),
和項目.pro
文件(QT += concurrent
)。
3. Qt命名空間
在Qt命名空間中,您會發現Qt庫中使用了各種各樣的標識符。在進入本主題的下一章之前,我們希望您能記住這些列表。
只是開個玩笑!我們只是想讓您知道,如果您碰巧需要使用命名空間,可以把它作為參考材料。
4. TMC練習的結構
講完基礎知識之后,該看一下TMC練習的結構組成了。
每個練習都位于每周主練習目錄中自己的子目錄中。該練習由根級別的.pro
文件以及幾個目錄組成。
根級別的.pro
文件是練習項目的項目文件。我們將在本章后面進一步討論項目文件。但是現在,我們將重點放在項目結構上。
用于測試您的練習的本地測試位于test_runner
目錄中。
如果您在弄清楚為什么您的練習不能通過測試時遇到了問題,并且您已經用盡了所有其他方法,那么可能值得查看測試運行程序文件。弄清楚測試的內容可能會給您一些線索,讓您知道代碼中可能存在的問題。如果有助于您更好的理解問題的話,您甚至可以修改本地測試。在極少的情況下,問題可能是由于測試本身是錯誤的。在這種情況下,我們建議加入課程頻道,看看其他人是否有同樣的問題。我們已經做了我們所能做的一切來確保這種情況不會發生,但總有特殊情況。
請注意,本地測試只是為了告訴您,您的練習是否完成并準備好提交。您無法根據自己的偏好修改測試,并期望通過提交一份未完成的作業來通過練習!我們將在您獲得分數之前在服務器上測試您的練習!有時候,服務器端可能會有隱藏的測試,以確保您不會根據測試的目的來嘗試完成練習,而是完成實際的練習來支持您的學習。
src
目錄是神奇個地方,它是我們編程的位置。
它包括每個練習項目的相關源文件和頭文件。在某些情況下,庫可能包含額外的目錄,在某些情況下,我們可能會要求您創建新的目錄。沒人知道!沒有人知道什么時候!沒有人知道!但我們稍后會算出來。
您是否已經注意到每個目錄都有自己的.pro
文件?這樣做的原因是,我們包含在練習目錄中的每一個子目錄實際上都是實際練習項目中的子項目。讓我們詳細介紹一下根目錄.pro
文件:
TEMPLATE = subdirs
SUBDIRS += \
src \
test_runner
test_runner.depends = src
它會告訴qmake
(我們將在本章的下一步討論它)該練習項目遵循一個名為subdirs
的構建模板,并定義了包含在該項目中的子目錄。使用子目錄模板要求每個聲明的子目錄都是其自己的項目,并且在子目錄中包含它自己的項目文件。最后,我們聲明test runner
子目錄依賴于src
目錄。這是因為我們想在構建test runner
之前構建您的練習,這樣test runner
就有東西要測試了。
5. qmake
qmake工具可以幫助您在各種平臺開發項目時簡化構建過程。它會自動生成Makefile,因此只需幾行信息即可創建Makefile。您還可以將qmake用于其他軟件項目,無論它是不是使用Qt編寫的。
qmake
根據項目文件中的信息生成一個Makefile
。項目文件使用擴展名.pro
,通常由Qt Creator中的項目模板創建。項目文件由開發人員處理,以指定他們qmake
要用于其項目的指令集,并且通常很簡單。不過您也可以為復雜的項目創建更復雜的項目文件。我們將在本章后面進一步討論項目文件,但由于qmake
使用的是存儲在項目文件中的信息,所以在談到qmake
時,我們無法避免地會談到它們的內容。
qmake
的行為受項目構建過程中的變量聲明的影響。其中一些聲明資源對每個平臺都是通用的,例如頭文件和源文件。其他的用于定制特定平臺上編譯器和鏈接器的行為。
讓我們再一次參考我們的練習結構來詳細說明,源目錄中的.pro
文件如下:
QT -= gui
TARGET = main
CONFIG += c++11 console
CONFIG -= app_bundle
win32 {
CONFIG -= debug_and_release debug_and_release_target
}
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
hello.cpp
HEADERS += \
hello.h
您可以參考01_HelloWorld
的目錄結構和文件組成。也可以參照qmake變量引用,并思考前面提到的.pro
文件代碼中的聲明。您要知道我們要告訴qmake
什么以及為什么。win32位可能不是完全不言自明的。
特定于平臺的變量遵循它們的擴展或修改的變量的命名模式,但在其名稱中包括相關平臺的名稱。例如,LIBS
可用于指定項目需要鏈接的庫列表。如下:
unix:LIBS += -L/usr/local/lib -lmath
win32:LIBS += c:/mylibs/math.lib
如果您想自己做一些探索,我們建議您查看qmake變量的完整列表,以便自行瀏覽。
6. .pro文件
在項目文件中,變量用于保存字符串列表。在最簡單的項目中,這些變量會告知qmake
要使用的配置選項,或者提供要在構建過程中使用的文件名和路徑。
qmake
會在每個項目文件中查找某些變量,并使用這些變量的內容來確定應該向Makefile
寫入什么。例如,HEADERS
和SOURCES
變量中的值列表用于聲明qmake
與項目文件位于同一目錄中的頭文件和源文件。
只要您使用qmake
,默認情況下就會包括Core和GUI模塊。
變量還可以在內部用于存儲值的臨時列表,現有的值列表可以用新值覆蓋或擴展。
以下代碼段說明了如何將值列表分配給變量:
HEADERS = mainwindow.h paintwidget.h
變量中的值列表以以下方式擴展:
SOURCES = main.cpp mainwindow.cpp \
paintwidget.cpp
CONFIG += console
注意:第一個賦值僅包含與HEADERS
變量在同一行上指定的值。第二個賦值SOURCES
使用反斜杠(\
)將變量中的值分成幾行。
7. Qt資源系統
Qt資源系統是一種獨立于平臺的方式,用于在應用程序的可執行文件中存儲應用程序資源(圖像、圖標、翻譯文件、數據等)。
資源在資源集合文件中qrc
指定:
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/icon.png</file>
<file>data.txt</file>
</qresource>
</RCC>
然后將該文件包含在.pro
文件中,如RESOURCES = application.qrc
。指定的文件將被壓縮并包裝為一個C++靜態數組。接著可以使用像QFile或圖像類型來訪問它們,就像其他任何文件一樣:
QIcon icon(":/images/icon.png")
QFile file(":/data.txt");
8. QDebug類
QDebug類提供了一個用于調試信息的輸出流。
當開發人員需要將調試或跟蹤信息寫入設備、文件、字符串或控制臺時,就會使用QDebug。
基本用途
在通常情況下,調用qDebug()
函數以獲得默認的QDebug對象以用于編寫調試信息很有用。
qDebug() << "Date:" << QDate::currentDate();
qDebug() << "Types:" << QString("String") << QChar('x') << QRect(0, 10, 50, 40);
qDebug() << "Custom coordinate type:" << coordinate;
QDebug
的構造函數會接受QtMsgType
值來構造一個QtDebugMsg
對象。類似地,qWarning()
,qCritical()
和qFatal()
也會返回相應的消息類型的QDebug對象。
這個類還為其他情況提供了一些構造函數,包括接收QFile或用于將調試信息寫入文件,套接字,其他進程等的任何其他QIODevice子類的構造函數。接收QString的構造函數用于寫入用于顯示或序列化的字符串。
格式化選項
格式化QDebug的輸出以便于閱讀。它在參數之間會自動添加空格,并為QString
,QByteArray
,QChar
的參數增加了引號。
您可以通過space()
,nospace()
,quote()
,noquote()
方法來調整這些選項。另外,可以將QTextStream
通過管道傳送到QDebug
流中。
使用QDebugStateSaver
會將格式更改限制為當前范圍。resetFormat()
將選項重置為默認選項。
將自定義類型寫入流
可以將許多標準類型寫入QDebug對象,而Qt提供了對大多數Qt值類型的支持。要添加對自定義類型的支持,您需要實現一個流操作符,如下面的示例所示:
QDebug operator<<(QDebug debug, const Coordinate &c)
{
QDebugStateSaver saver(debug);
debug.nospace() << '(' << c.x() << ", " << c.y() << ')';
return debug;
}
9. 輸出調試信息
qDebug,qWarning,qCritical和qFatal是Qt全局聲明中定義的函數。這些函數采用格式化字符串和參數列表,類似于C語言的printf()
函數。格式應為Latin-1字符串。要禁止這些類型中的任何一種,您可以使用qInstallMessageHandler安裝自己的消息處理程序。函數使用定義的調試/嚴重/致命/警告消息調用消息處理程序。它們調用消息處理程序,如果沒有消息處理程序,則將消息打印到stderr
。在Windows上,大多數情況下,該消息會發送到調試器。
qDebug(const char *message, ...)
在Windows下,如果消息是控制臺應用程序,則將消息發送到控制臺。否則,它將被發送到調試器。如果在編譯過程中定義了QT_NO_DEBUG_OUTPUT
,則此函數不執行任何操作。
例如:
qDebug("Items in list: %d", myList.size());
如果導入QtDebug
,還可以使用更方便的語法:
qDebug() << "Brush:" << myQBrush << "Other value:" << i;
使用此語法,該函數返回一個QDebug對象,該對象配置為使用QtDebugMsg消息類型。它會自動在每個項目之間放置一個空格,并在末尾輸出換行符。它支持許多C++和Qt類型。
導入QtDebug
同樣允許以使用qInfo
,qCritical
和qWarning
等效語法。
qCritical(const char *message, ...)
如果環境變量QT_FATAL_CRITICALS
不為空,則退出。
例如:
void load(const QString &fileName)
{
QFile file(fileName);
if (!file.exists())
qCritical("File '%s' does not exist!", qUtf8Printable(fileName));
}
-
qWarning(const char *message, ...)
如果在編譯期間定義QT_NO_WARNING_OUTPUT
,則此函數不執行任何操作。如果在環境變量QT_FATAL_WARNINGS
中的計數器對應的第n個警告時,它就會退出。也就是說,如果環境變量包含值1,它將在第一條消息上退出;如果它定義為10,它將在第10條消息上退出。任何非數字值都等于1。
例如:
void f(int c)
{
if (c > 200)
qWarning("f: bad argument, c == %d", c);
}
qFatal(const char *message, ...)
如果使用默認消息處理程序,則此函數將中止以創建核心轉儲。在Windows上,對于調試版本,此功能將報告_CRT_ERROR
使您能夠將調試器連接到應用程序。
例如:
int divide(int a, int b)
{
if (b == 0)
qFatal("divide: cannot divide by zero");
return a / b;
}
10. 影子構建
成功構建第一個Qt項目后,您可能會對構建的二進制文件感興趣。默認情況下,Qt Creator將項目作為影子構建到一個單獨的目錄(`build-ProjectName- *`)中,該目錄與源目錄分開。qmake
也可以生成源代碼內部版本,但是不建議這樣做。影子構建的好處是保持該目錄的清潔,這使得在Kit或構建配置之間進行更改的速度更快。
嘿! 現在是我們第一次練習的時候了。這將是一個簡單的過程,請放心。只需從TMC下載練習模板,打開項目,然后轉到
hello.cpp
。
在world()
函數中,寫上“Hello world”作為qDebug
消息,并寫上“Don't panic!” 作為qWarning
消息。