QT學習筆記和踩坑記錄(第一天)
文章目錄
QT學習筆記:
0001 註釋的快捷鍵
Ctrl+/ 可以多行註釋或者取消註釋。
0002 檢視幫助文件
F1跳轉到要檢視的程式碼的幫助文件,在按一次F1,展開幫助文件。
0003 Q_UNUSED
Q_UNUSED(變數)可以讓沒被使用的變數不報令人討厭的警告。
0004 Q_OBJECT
只有繼承了QObject類的類,才具有訊號槽的能力。所以,為了使用訊號槽,必須繼承QObject。凡是QObject類(不管是直接子類還 是間接子類),都應該在第一行程式碼寫上Q_OBJECT。
0005 setParent()
如果不指定父物件,物件和物件(視窗和視窗)沒有關係,獨立
a指定b為它的父物件,a就會放在b的上面,即a成為b的子控制元件。
指定父物件,有兩種方式:
1)a.setParent(b)
2)通過建構函式傳參,即在例項a的時候將b做為它的引數傳進去
只需要父物件b顯示,上面的子物件a自動顯示。
0006 QPainter繪圖
QPainter繪圖的時候,原點在左上角,向右下方繪圖,可以通過painter.translate()和painter.rotate()函式改變原點位置和旋轉圖形。
0007 qDebug
標頭檔案QDebug,qDebug函式可用於列印某些變數的值,與cout的用法一樣,一般用於除錯。
0008 connect函式詳解
connect函式用於將一個訊號和槽函式相關聯,當訊號觸發時呼叫該槽函式,兩者可以位於不同的類。
QT4的connect函式詳解:
函式定義:connect(Sender,SIGNAL(signal),Receiver,SLOT(slot));
Sender是訊號的傳送者,如當一個按鈕被點選時要發射點擊的訊號,那麼傳送者就是這個按鈕本身。
**SIGNAL(signal)**是訊號名,可以是自定義的訊號,也可以是QT自帶的訊號。
Receiver是訊號的接收者、槽函式的擁有者。
**SLOT(slot)**是需要呼叫的槽函式,即使是在當前類中,也需要加類名限定該函式。
可能出現的問題:
QT4的connect函式實際上利用SIGNAL
和SLOT
這兩個巨集,把其後的函式名轉換成一個字串。隨後,moc 將會掃描 全部檔案,將所有的 signal 和 slot 提取出來做成一個對映表。QObject::connect()
函式則會從這個對映表裡面找到該·· 字串,從 signal 的名字就可以找到 slot 的名字,因此也就知道了在 signal emit 的時候,該去呼叫哪一個 slot 函式。
1)沒有編譯期檢查:因為函式名被處理成字串,所有的檢查都是在執行時完成的。這就是為什麼有時會發生編譯通過 了,但 slot 並沒有被呼叫。此時,你就應該去檢查 console 的輸出,看看有沒有什麼 warning 說明 connect 並沒有成功。
2)因為處理的是字串,所以 slot 中的型別名字必須用 signal 的完全一致,而且在標頭檔案中的和實際 connect 語句中的 也必須一致。也就是說,如果你使用了 typedef 或者 namespace,connect 就可能不成功(在 Qt 5 之前的版本中,我們當 然也可以使用namespace,但是必須保證標頭檔案中的和 connect 語句中的文字完全一致)。
QT5的connect函式詳解:
函式定義:connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);
各個引數與之前的類似,優點是可以連線到任意函式,缺點是在使用過載的訊號和函式的時候得定義函式指標。
例子:
connect(&sm->clicked_big_window,&QPushButton::pressed,this,&MainWidget::toBigWindow);
sm是前面的一個例項,將sm中的clicked_big_window按鈕作為訊號的傳送者,當發射QPushButton::pressed訊號, 即按鈕被點選的訊號時,呼叫當前物件的(this)的,&MainWidget::toBigWindow函式。
0009 signals訊號詳解
signals訊號詳解:
1)訊號必須有signals關鍵字來宣告
2)訊號沒有返回值,但可以有引數
3)訊號就是函式的宣告,只需宣告,無需定義
4)使用:emit mySiganal()
5)訊號可以過載
例子:
signals:
void mySignal();
void mySignal(int,QString);
6)訊號過載的時候,為了QT5的connect函式不產生二義性(報錯),需在connect之前定義該訊號的函式指標,用該函式指標代替 connect的第二個引數
如:
//無參的mySignal
void (XXXX::*funSignal)()=&XXXX::mySignal;
connect(&XXXX,funSignal,XXXX,&XXXX::XXXX);
//有參的mySignal
void (XXXX::*testSignal)(int ,QString)=&XXXX::mySignal;
connect(&xxxx,funSignal,XXXX,&XXXX::XXXX);
0010 QT中的Lambda表示式
Lambda表示式是C++11新增的新特性,想在QT中使用的話,得在專案檔案(.pro)中加入 CONFIG += C++11
QPushButton *b= new QPushButton(this);
b->setTest("Lambda表示式");
connect(b,&QPushButton::released,
[b]()//匿名內部類
{
//此處相當於槽函式
b->setTest("Lambda表示式2");
}
)
/*
[]的作用是將外部的變數,以值傳遞的方式傳遞進這個匿名內部類
[=]表示把外部所有區域性變數、勒種所有成員傳進去
[]() mutable 表示對外部變數不僅可讀還可寫
*/
0011 座標系統
主視窗相對於螢幕、子控制元件相對於父視窗,座標系統的原點在左上角。
0012 記憶體回收機制
1)指定父物件後
2)直接或間接繼承於QObject
子物件如果是動態分配空間(new)的話,不需要手動釋放(delete),系統會自動釋放,即該子物件的解構函式會被自動呼叫。
QT踩坑記錄:
0001
QT任何路徑下都不能出現中文、空格 。
0002
註釋只能用//,/**/會報錯。
0003
error: LNK2001: 無法解析的外部符號 “public: virtual struct QMetaObject const * __cdecl
解決辦法:
編譯出錯是因為沒有生成moc_mainwindowprivate.cpp檔案造成的。
如果新新增QObject派生類到您的專案,則必須再次執行qmake,即
1、清理專案(非必須)
2、執行qmake(必須)
3、構建專案(必須)
否則,如果在QObject繼承的類上進行增量構建,那麼您將擁有過時的moc檔案,或者乾脆沒有moc檔案。