[Qt教程] 第43篇 进阶(三)对象树与拥有权
生活随笔
收集整理的這篇文章主要介紹了
[Qt教程] 第43篇 进阶(三)对象树与拥有权
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
[Qt教程]?第43篇 進(jìn)階(三)對象樹與擁有權(quán)
??|?查看: 255|?回復(fù): 1| 對象樹與擁有權(quán) 版權(quán)聲明 該文章原創(chuàng)于Qter開源社區(qū) 導(dǎo)語 學(xué)習(xí)完前面的內(nèi)容,大家對應(yīng)用Qt編程應(yīng)該已經(jīng)有了一個(gè)大概的印象。后面的內(nèi)容我們將介紹Qt中的一些核心機(jī)制,它們是構(gòu)成Qt的基礎(chǔ),包括對象模型、信號和槽、對象樹與擁有權(quán)等。在前面使用Qt編程時(shí),大家對一些內(nèi)容可能存在疑惑,學(xué)習(xí)完下面的知識,可以幫助大家更好的使用Qt進(jìn)行編程。 環(huán)境:Windows Xp + Qt 4.8.5+QtCreator2.8.0 目錄 一、對象模型 二、元對象系統(tǒng) 三、對象樹與擁有權(quán) 正文 一、對象模型 標(biāo)準(zhǔn)C++對象模型可以在運(yùn)行時(shí)非常有效的支持對象范式(object paradigm),但是它的靜態(tài)特性在一些問題領(lǐng)域中不夠靈活。圖形用戶界面編程不僅需要運(yùn)行時(shí)的高效性,還需要高度的靈活性。為此,Qt在標(biāo)準(zhǔn)C++對象模型的基礎(chǔ)上添加了一些特性,形成了自己的對象模型。這些特性有:
Qt的這些特性都是在遵循標(biāo)準(zhǔn)C++規(guī)范內(nèi)實(shí)現(xiàn)的,使用這些特性都必須要繼承自QObject類。其中對象通信機(jī)制和動(dòng)態(tài)屬性系統(tǒng),還需要元對象系統(tǒng)(Meta-ObjectSystem)的支持。關(guān)于對象模型的介紹,大家可以在幫助中查看Object Model關(guān)鍵字。 二、元對象系統(tǒng) Qt中的元對象系統(tǒng)(Meta-Object System)提供了對象間通信的信號和槽機(jī)制、運(yùn)行時(shí)類型信息和動(dòng)態(tài)屬性系統(tǒng)。元對象系統(tǒng)是基于以下三個(gè)條件的:
其中moc工具讀取一個(gè)C++源文件,如果它發(fā)現(xiàn)一個(gè)或者多個(gè)類的聲明中包含有Q_OBJECT宏,便會(huì)另外創(chuàng)建一個(gè)C++源文件(就是在項(xiàng)目目錄中的debug目錄下看到的以moc開頭的C++源文件),其中包含了為每一個(gè)類生成的元對象代碼。這些產(chǎn)生的源文件或者被包含進(jìn)類的源文件中,或者和類的實(shí)現(xiàn)同時(shí)進(jìn)行編譯和鏈接。 元對象系統(tǒng)主要是為了實(shí)現(xiàn)信號和槽機(jī)制才被引入的,不過除了信號和槽機(jī)制以外,元對象系統(tǒng)還提供了其他一些特性:
除了這些特性外,還可以使用qobject_cast()函數(shù)來對QObject類進(jìn)行動(dòng)態(tài)類型轉(zhuǎn)換,這個(gè)函數(shù)的功能類似于標(biāo)準(zhǔn)C++中的dynamic_cast()函數(shù),但它不再需要RTTI的支持。這個(gè)函數(shù)嘗試將它的參數(shù)轉(zhuǎn)換為尖括號中的類型的指針,如果是正確的類型則返回一個(gè)非零的指針,如果類型不兼容則返回0。例如: QObject *obj = new MyWidget; QWidget *widget = qobject_cast<QWidget *>(obj); 信號和槽機(jī)制是Qt的核心內(nèi)容,而信號和槽機(jī)制必須依賴于元對象系統(tǒng),所以它是Qt中很關(guān)鍵的內(nèi)容。關(guān)于元對象系統(tǒng)的知識,可以在Qt中查看The Meta-Object System關(guān)鍵字。 三、對象樹與擁有權(quán) Qt中使用對象樹(object tree)來組織和管理所有的QObject類及其子類的對象。當(dāng)創(chuàng)建一個(gè)QObject時(shí),如果使用了其他的對象作為其父對象(parent),那么這個(gè)QObject就會(huì)被添加到父對象的children()列表中,這樣當(dāng)父對象被銷毀時(shí),這個(gè)QObject也會(huì)被銷毀。實(shí)踐表明,這個(gè)機(jī)制非常適合于管理GUI對象。例如,一個(gè)QShortcut(鍵盤快捷鍵)對象是相應(yīng)窗口的一個(gè)子對象,所以當(dāng)用戶關(guān)閉了這個(gè)窗口時(shí),這個(gè)快捷鍵也可以被銷毀。 QWidget作為能夠在屏幕上顯示的所有部件的基類,擴(kuò)展了對象間的父子關(guān)系。一個(gè)子對象一般也就是一個(gè)子部件,因?yàn)樗鼈円@示在父部件的區(qū)域之中。例如,當(dāng)關(guān)閉一個(gè)消息對話框(message box)后要銷毀它時(shí),消息對話框中的按鈕和標(biāo)簽也會(huì)被銷毀,這也正是我們所希望的,因?yàn)榘粹o和標(biāo)簽是消息對話框的子部件。當(dāng)然,我們也可以自己來銷毀一個(gè)子對象。關(guān)于這一部分的內(nèi)容,大家可以在幫助索引中查看Object Trees &Ownership關(guān)鍵字。 在前面的Qt編程中我們應(yīng)該看到過很多使用new來創(chuàng)建一個(gè)部件,但是卻沒有使用delete來進(jìn)行釋放的問題。這里再來研究一下這個(gè)問題。 新建Qt Gui應(yīng)用,項(xiàng)目名稱為“myOwnership”,基類選擇QWidget,然后類名保持“Widget”不變。完成后向項(xiàng)目中添加新文件,模板選擇C++ Class,類名為“MyButton”,基類為“QPushButton”,類型信息選擇“繼承自QWidget”。添加完文件后在mybutton.h文件中添加析構(gòu)函數(shù)的聲明: ~MyButton(); 然后到mybutton.cpp文件中添加頭文件#include <QDebug>并定義析構(gòu)函數(shù): MyButton::~MyButton() { ? ?qDebug() << "delete button"; } 這樣當(dāng)MyButton的對象被銷毀時(shí),就會(huì)輸出相應(yīng)的信息。這里定義析構(gòu)函數(shù),只是為了更清楚的看到部件的銷毀過程,其實(shí)一般在構(gòu)建新類時(shí)不需要實(shí)現(xiàn)析構(gòu)函數(shù)。下面在widget.cpp文件中進(jìn)行更改,添加頭文件: #include?"mybutton.h" #include<QDebug> 在構(gòu)造函數(shù)中添加代碼: MyButton?*button?=?new?MyButton(this);? ??//?創(chuàng)建按鈕部件,指定widget為父部件 button->setText(tr("button")); 更改析構(gòu)函數(shù): Widget::~Widget() { ? ??delete?ui;? ??qDebug() << "delete widget";} Widget類的析構(gòu)函數(shù)中默認(rèn)的已經(jīng)有了銷毀ui的語句,這里又添加了輸出語句。當(dāng)Widget窗口被銷毀時(shí),將輸出信息。下面運(yùn)行程序,然后關(guān)閉窗口,在QtCreator的應(yīng)用程序輸出欄中的輸出信息為: delete widget delete button 可以看到,當(dāng)關(guān)閉窗口后,因?yàn)樵摯翱谑琼攲哟翱?#xff0c;所以應(yīng)用程序要銷毀該窗口部件(如果不是頂層窗口,那么關(guān)閉時(shí)只是隱藏,不會(huì)被銷毀),而當(dāng)窗口部件銷毀時(shí)會(huì)自動(dòng)銷毀其子部件。這也就是為什么在Qt中經(jīng)常只看到new操作而看不到delete操作的原因。再來看一下main.cpp文件,其中Widget對象是建立在棧上的: Widget?w; w.show(); 這樣對于對象w,在關(guān)閉程序時(shí)會(huì)被自動(dòng)銷毀。而對于Widget中的部件,如果是在堆上創(chuàng)建(使用new操作符),那么只要指定Widget為其父窗口就可以了,也不需要進(jìn)行delete操作。整個(gè)應(yīng)用程序關(guān)閉時(shí),會(huì)去銷毀w對象,而此時(shí)又會(huì)自動(dòng)銷毀它的所有子部件,這些都是Qt的對象樹所完成的。 所以,對于規(guī)范的Qt程序,我們要在main()函數(shù)中將主窗口部件創(chuàng)建在棧上,例如“Widget w;”,而不要在堆上進(jìn)行創(chuàng)建(使用new操作符)。對于其他窗口部件,可以使用new操作符在堆上進(jìn)行創(chuàng)建,不過一定要指定其父部件,這樣就不需要再使用delete操作符來銷毀該對象了。 還有一種重定義父部件(reparented)的情況,例如,將一個(gè)包含其他部件的布局管理器應(yīng)用到窗口上,那么該布局管理器和其中的所有部件都會(huì)自動(dòng)將它們的父部件轉(zhuǎn)換為該窗口部件。在widget.cpp文件中添加頭文件#include?<QHBoxLayout>,然后在構(gòu)造函數(shù)中繼續(xù)添加代碼: MyButton?*button2?=?new?MyButton; MyButton?*button3?=?new?MyButton; QHBoxLayout?*layout?=?new?QHBoxLayout; layout->addWidget(button2); layout->addWidget(button3); setLayout(layout);? ?? ?//?在該窗口中使用布局管理器 這里創(chuàng)建了兩個(gè)MyButton和一個(gè)水平布局管理器,但是并沒有指定它們的父部件,現(xiàn)在各個(gè)部件的擁有權(quán)(ownership)不是很清楚。但是當(dāng)使用布局管理器來管理這兩個(gè)按鈕,并且在窗口中使用這個(gè)布局管理器后,這兩個(gè)按鈕和水平布局管理器都將重定義父部件而成為窗口Widget的子部件。可以使用children()函數(shù)來獲取一個(gè)部件的所有子部件的列表,例如在構(gòu)造函數(shù)中再添加如下代碼: qDebug() << children();? ??//?輸出所有子部件的列表 這時(shí)大家可以運(yùn)行一下程序,查看應(yīng)用程序輸出欄中的信息,然后根據(jù)自己的想法更改一下程序,來進(jìn)一步體會(huì)Qt中對象樹的概念。 結(jié)語 Qt中的對象樹很好地解決了父子部件的關(guān)系,對于Gui編程是十分方便的,在創(chuàng)建部件時(shí)我們只需要關(guān)注它的父部件,這樣就不用再考慮其銷毀問題了。下一節(jié),我們將講解Qt中的信號和槽的內(nèi)容。 涉及到的源碼:??myOwnership.rar?? |
總結(jié)
以上是生活随笔為你收集整理的[Qt教程] 第43篇 进阶(三)对象树与拥有权的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Qt教程] 第20篇 2D绘图(十)图
- 下一篇: [Qt教程] 第44篇 进阶(四)信号和