文章目錄
- 一 、對象樹是什么?
- 二、信號和槽的基本概念
- 2.1 信號
- 2.2 槽
- 2.3 松散耦合
- 2.4 特點
- 三、示例
- 總結
一 、對象樹是什么?
對象樹是由父類和若干子類對象組成,而子類也可以由若干孫類。
QT中的對象樹是以QObject為起始父類來完成樹的構建的,如下圖所示。
當創建子類對象(QObject )的時候,會傳遞一個parent指針給子類的構造函數,該指針就是父對象指針。
//QWidget 為myWidget的父類
myWidget::myWidget(QWidget *parent): QWidget(parent)
{
}class myWidget : public QWidget
{Q_OBJECT
//parent 父對象指針傳遞給子類的構造函數。
public:myWidget(QWidget *parent = 0);
};
所以在創建 QObject 對象時,會提供一個父對象的指針給構造函數,QObject 對象就會自動添加到其父對象的 children() 列表。然后當父對象進行析構的時候,這個子對象列表中的所有對象都會被析構,當析構子對象的時候,會自動從父對象的子對象列表中刪除。
這種對象樹機制的優點在于析構父類的析構時,子類對象會自動銷毀,這樣就不需要關注控件內存的銷毀情況。
但也會存在特殊情況會造成QT程序內存泄漏問題,這樣就需要我們手動刪除或者調用析構函數。
1:parent指針不會區分child對象是new出來的還是從棧上分配的,如果delete棧上的內存,就會發生錯誤。避免這一情況的方法就是全部使用new來開辟空間。
2:可以嘗試采用智能指針QPointer(模板類)的方法來自動銷毀內存空間。
3:Qt的對象清理器QObjectCleanupHandler也可以自動刪除所有監視對象。
二、信號和槽的基本概念
信號槽機制類似于C#中回調函數的概念,我們知道,回調函數的本質是函數作為參數在合適的時候(條件成立時)被某一特定的事件調用的方法,而信號槽機制是如果觸發事件,對象就會發出信號給接收者,然后調用綁定的槽函數,其中相似之處在于這兩種方式都會在滿足某一條件時觸發事件,信號類似于條件達成的方法,槽函數就像被委托調用的方法。
C#是通過委托來實現函數作為參數傳遞的,信號槽機制則是通過連接的方式實現的信號和槽的綁定。
2.1 信號
信號signal也是由不同的方法組成的,例如,按鈕的信號有9種,分別繼承自三個類QAbstractButton,QWidget,QObject:
分別表示點擊、按壓、松開、開關等不同狀態。
我們可以在自定義類里自定義信號:
signals://自定義信號寫到signals下//返回值是void,只需要聲明,不需要實現//可以有參數,可以重載//emit hungry();來發送信號void hungry();void hungry(QString food);
2.2 槽
槽(slot)的本質是類的成員函數,其參數可以是任意類型的,可以實現不同的功能,如關閉,隱藏,下降,上升等。例如QWidget類下槽函數包括:
自定義槽:
public slots://返回值是void,需要聲明,也需要實現//可以有參數,也可以重載void eat();void eat(QString food);
2.3 松散耦合
信號和槽是松散耦合的。
松散耦合是指槽可以與信號連接(connect)在一起,只有連接的信號被激發的時候,才能調用槽函數。
2.4 特點
1:一個信號可以連接多個槽函數。多個信號也可以連接同一個槽函數。
2:信號和槽函數,參數必須一一對應。
三、示例
使用一個定時器的demo做一個簡單的示例。
定義兩個定時器,實現顯示數字的功能。
Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);//啟動定時器,每隔1s啟動一次id1 =startTimer(1000);id2 =startTimer(2000);//定時器的一種方式QTimer *timer = new QTimer(this);timer->start(500);//超時信號和顯示槽函數建立連接,timer一超時便發送一個信號setText方法遞增1connect(timer,&QTimer::timeout,[=](){static int num = 1;ui->label_3->setText(QString::number(num++));});//點擊暫停按鈕實現connect(ui->pushButton,&QPushButton::clicked,[=](){timer->stop();});
}
另外一種方法需要定義定時器的事件,用來顯示數字。
void Widget::timerEvent(QTimerEvent *event)
{//number()方法轉stringif(event->timerId() == id1){static int num = 1;ui->label->setText(QString::number(num++));}if(event->timerId() == id2){static int num2 = 1;ui->label_2->setText(QString::number(num2++));}
}
總結
對象樹和信號槽機制使QT界面功能的搭建變得簡易和靈活,缺點在于由于需要遍歷所有關聯造成性能降低。