摘要:本文主要是利用嚮導創建了第一個qt工程文件,主要介紹了工程文件的結構、main函數、按鈕的創建、qt中的對象樹、座標系、qt中的信號和槽等概念。
一、工程文件的結構
利用qt導向創建好工程文件之後,會自動生成main函數、頭文件、源文件和Pro文件,以下圖:數組
二、main函數
在這個main函數中,主要建立了一個窗口對象w,調用構造函數,實現一些按鈕、信號和槽的功能。函數
1 #include "mywidget.h" //包含頭文件 2 #include <QApplication> //包含QApplication頭文件 3 4 //程序入口 argc命令行變量的數量 argv命令行變量數組 5 int main(int argc, char *argv[]) 6 { 7 QApplication a(argc, argv); //a 應用程序對象,對於Qt項目必須有應用程序對象,並且有且僅有一個 8 MyWidget w; //建立一個MyWidget對象 9 w.show(); //建立出的窗口對象並不會直接顯示,須要調用show方法 10 11 return a.exec(); //進入消息循環機制,阻塞狀態 12 // while(true) 13 // { 14 // if(點擊叉子) 15 // break; 16 // } 17 }
三、myweiget.cpp和myweiget.h
在頭文件中,重點注意類中加了「Q_OBJECT」,構造函數有默認參數。工具
1 #ifndef MYWIDGET_H 2 #define MYWIDGET_H 3 4 #include <QWidget> 5 6 //繼承於QWidget 7 class MyWidget : public QWidget 8 { 9 //支持Qt中的信號和槽使用 10 Q_OBJECT 11 12 public: 13 MyWidget(QWidget *parent = 0); //構造 14 ~MyWidget(); //析構 15 }; 16 17 #endif // MYWIDGET_H
在源文件中,注意函數變量的名字兩個單詞之間用大寫字母隔開;注意建立按鈕的兩種方法;爲按鈕添加文本,設置按鈕位置,設置按鈕大小;重置窗口的大小和窗口名稱等方法。重點是學會查看幫助文檔。測試
1 #include "mywidget.h" 2 #include<QPushButton> 3 #include "mybutton.h" 4 #include <QDebug> 5 6 MyWidget::MyWidget(QWidget *parent) 7 : QWidget(parent) 8 { 9 QPushButton * btn =new QPushButton; 10 11 // btn->show(); 12 //btn應該依賴於主窗口 13 btn->setParent(this); 14 //顯示文字 15 btn->setText("德瑪"); 16 17 //第二種建立方式 18 QPushButton * btn2 = new QPushButton("德瑪西亞",this); 19 //移動窗口 20 btn2->move(100,100); 21 //重置窗口大小 22 resize(960,640); 23 24 //btn可不能夠 resize? 能夠 25 btn2->resize(50,50); 26 27 //設置窗口標題名稱 28 this->setWindowTitle("德瑪西亞萬歲"); 29 30 //對象樹 31 MyButton * myBtn = new MyButton(); 32 myBtn->setParent(this); 33 myBtn->move(200,200); 34 myBtn->setText("個人按鈕"); 35 36 //窗體的座標系 37 //左上角爲 0 0 點 38 // x 以右側爲正方向 y 如下側爲正方向 39 40 //需求 點擊「個人按鈕」 ,關閉窗口 41 //鏈接信號槽的關鍵字 connect 42 //4個參數 參數1 信號發送者 參數2 發送的信號 參數3 信號的接受者 參數4 處理的槽函數 43 //參數2 和參數4 須要的都是函數地址 44 45 connect(myBtn,&QPushButton::clicked,this,&MyWidget::close); 46 47 } 48 49 MyWidget::~MyWidget() 50 { 51 qDebug("MyWidget析構了!"); 52 }
四、對象樹
先來看一幅圖:ui
(1)在qt中,QObject是以對象樹的形式組織起來的。
- 當你建立一個QObject對象時,會看到QObject的構造函數接收一個QObject指針做爲參數,這個參數就是 parent,也就是父對象指針。這至關於,在建立QObject對象時,能夠提供一個其父對象,咱們建立的這個QObject對象會自動添加到其父對象的children()列表。例如上面的3中的構造函數:MyWidget::MyWidget(QWidget *parent): QWidget(parent)
- 當父對象析構的時候,這個列表中的全部對象也會被析構。(注意,這裏的父對象並非繼承意義上的父類!)這種機制在 GUI 程序設計中至關有用。例如,一個按鈕有一個QShortcut(快捷鍵)對象做爲其子對象。當咱們刪除按鈕的時候,這個快捷鍵理應被刪除。這是合理的。
(2)QWidget是可以在屏幕上顯示的一切組件的父類。
- QWidget繼承自QObject,所以也繼承了這種對象樹關係。一個孩子自動地成爲父組件的一個子組件。所以,它會顯示在父組件的座標系統中,被父組件的邊界剪裁。例如,當用戶關閉一個對話框的時候,應用程序將其刪除,那麼,咱們但願屬於這個對話框的按鈕、圖標等應該一塊兒被刪除。事實就是如此,由於這些都是對話框的子組件。
- 固然,咱們也能夠本身刪除子對象,它們會自動從其父對象列表中刪除。好比,當咱們刪除了一個工具欄時,其所在的主窗口會自動將該工具欄從其子對象列表中刪除,而且自動調整屏幕顯示。
- Qt 引入對象樹的概念,在必定程度上解決了內存問題。
(3)當一個QObject對象在堆上建立的時候,Qt 會同時爲其建立一個對象樹。不過,對象樹中對象的順序是沒有定義的。這意味着,銷燬這些對象的順序也是未定義的。
(4)任何對象樹中的 QObject對象 delete 的時候,若是這個對象有 parent,則自動將其從 parent 的children()列表中刪除;若是有孩子,則自動 delete 每個孩子。Qt 保證沒有QObject會被 delete 兩次,這是由析構順序決定的。
(5)注意的問題:
若是QObject在棧上建立,Qt 保持一樣的行爲。正常狀況下,這也不會發生什麼問題。來看下下面的代碼片斷:this
1 { 2 QWidget window; 3 QPushButton quit("Quit", &window); 4 }
做爲父組件的 window 和做爲子組件的 quit 都是QObject的子類(事實上,它們都是QWidget的子類,而QWidget是QObject的子類)。這段代碼是正確的,quit 的析構函數不會被調用兩次,由於標準 C++要求,局部對象的析構順序應該按照其建立順序的相反過程。所以,這段代碼在超出做用域時,會先調用 quit 的析構函數,將其從父對象 window 的子對象列表中刪除,而後纔會再調用 window 的析構函數。spa
可是,若是咱們使用下面的代碼:命令行
1 { 2 QPushButton quit("Quit"); 3 QWidget window; 4 quit.setParent(&window); 5 }
狀況又有所不一樣,析構順序就有了問題。咱們看到,在上面的代碼中,做爲父對象的 window 會首先被析構,由於它是最後一個建立的對象。在析構過程當中,它會調用子對象列表中每個對象的析構函數,也就是說, quit 此時就被析構了。而後,代碼繼續執行,在 window 析構以後,quit 也會被析構,由於 quit 也是一個局部變量,在超出做用域的時候固然也須要析構。可是,這時候已是第二次調用 quit 的析構函數了,C++ 不容許調用兩次析構函數,所以,程序崩潰了。設計
由此咱們看到,Qt 的對象樹機制雖然幫助咱們在必定程度上解決了內存問題,可是也引入了一些值得注意的事情。這些細節在從此的開發過程當中極可能時不時跳出來煩擾一下,因此,咱們最好從開始就養成良好習慣,在 Qt 中,儘可能在構造的時候就指定 parent 對象,而且大膽在堆上建立。指針
(6)總結:
- 全部new出來的對象 不用管釋放
- 緣由 children表中的對象會在窗口關閉後進行自動釋放
(7)測試代碼
mybutton.h
1 #ifndef MYBUTTON_H 2 #define MYBUTTON_H 3 4 #include <QWidget> 5 #include <QPushButton> 6 7 class MyButton : public QPushButton 8 { 9 Q_OBJECT 10 public: 11 explicit MyButton(QWidget *parent = 0); 12 ~MyButton(); 13 signals: 14 15 public slots: 16 }; 17 18 #endif // MYBUTTON_H
mybutton.cpp
1 #include "mybutton.h" 2 #include <QDebug> 3 MyButton::MyButton(QWidget *parent) : QPushButton(parent) 4 { 5 6 } 7 8 MyButton::~MyButton() 9 { 10 qDebug() << "MyButton調用析構了!"; 11 12 }
上面代碼的執行結果是:
MyWidget析構了!
MyButton調用析構了!
這樣的析構順序和我咱們想象的不太一致,咱們會認爲是先析構按鈕再析構窗口,然而顯示的結果卻不是這樣的。實際上咱們的想法是正確的,這是由於在執行到窗口析構的過程當中,會出現按鈕的析構,等按鈕析構完成之後,再返回窗口析構。
五、窗口的座標系
原點在左上角
六、信號槽的基本使用
具體的使用見代碼