日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[Qt教程] 第43篇 进阶(三)对象树与拥有权

發布時間:2024/4/20 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Qt教程] 第43篇 进阶(三)对象树与拥有权 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

[Qt教程]?第43篇 進階(三)對象樹與擁有權

樓主 ?發表于 2013-9-12 16:39:33?|?查看: 255|?回復: 1
對象樹與擁有權
版權聲明
該文章原創于Qter開源社區

導語

學習完前面的內容,大家對應用Qt編程應該已經有了一個大概的印象。后面的內容我們將介紹Qt中的一些核心機制,它們是構成Qt的基礎,包括對象模型、信號和槽、對象樹與擁有權等。在前面使用Qt編程時,大家對一些內容可能存在疑惑,學習完下面的知識,可以幫助大家更好的使用Qt進行編程。

環境:Windows Xp + Qt 4.8.5+QtCreator2.8.0

目錄

一、對象模型 二、元對象系統 三、對象樹與擁有權

正文

一、對象模型
標準C++對象模型可以在運行時非常有效的支持對象范式(object paradigm),但是它的靜態特性在一些問題領域中不夠靈活。圖形用戶界面編程不僅需要運行時的高效性,還需要高度的靈活性。為此,Qt在標準C++對象模型的基礎上添加了一些特性,形成了自己的對象模型。這些特性有:
  • 一個強大的無縫對象通信機制——信號和槽(signals and slots);
  • 可查詢和可設計的對象屬性系統(object properties);
  • 強大的事件和事件過濾器(events and event filters);
  • 通過上下文進行國際化的字符串翻譯機制(string translation for internationalization);
  • 完善的定時器(timers)驅動,使得可以在一個事件驅動的GUI中處理多個任務;
  • 分層結構的、可查詢的對象樹(object trees),它使用一種很自然的方式來組織對象擁有權(object ownership);
  • 守衛指針即QPointer,它在引用對象被銷毀時自動將其設置為0;
  • 動態的對象轉換機制(dynamic cast);

Qt的這些特性都是在遵循標準C++規范內實現的,使用這些特性都必須要繼承自QObject類。其中對象通信機制和動態屬性系統,還需要元對象系統(Meta-ObjectSystem)的支持。關于對象模型的介紹,大家可以在幫助中查看Object Model關鍵字。

二、元對象系統
Qt中的元對象系統(Meta-Object System)提供了對象間通信的信號和槽機制、運行時類型信息和動態屬性系統。元對象系統是基于以下三個條件的:
  • 該類必須繼承自QObject類;
  • 必須在類的私有聲明區聲明Q_OBJECT宏(在類定義時,如果沒有指定public或者private,則默認為private);
  • 元對象編譯器Meta-Object Compiler(moc),為QObject的子類實現元對象特性提供必要的代碼。

其中moc工具讀取一個C++源文件,如果它發現一個或者多個類的聲明中包含有Q_OBJECT宏,便會另外創建一個C++源文件(就是在項目目錄中的debug目錄下看到的以moc開頭的C++源文件),其中包含了為每一個類生成的元對象代碼。這些產生的源文件或者被包含進類的源文件中,或者和類的實現同時進行編譯和鏈接。

元對象系統主要是為了實現信號和槽機制才被引入的,不過除了信號和槽機制以外,元對象系統還提供了其他一些特性:
  • QObject::metaObject()函數可以返回一個類的元對象,它是QMetaObject類的對象;
  • QMetaObject::className()可以在運行時以字符串形式返回類名,而不需要C++編輯器原生的運行時類型信息(RTTI)的支持;
  • QObject::inherits()函數返回一個對象是否是QObject繼承樹上一個類的實例的信息;
  • QObject::tr()和QObject::trUtf8()進行字符串翻譯來實現國際化;
  • QObject::setProperty()和QObject::property()通過名字來動態設置或者獲取對象屬性;
  • QMetaObject::newInstance()構造該類的一個新實例。

除了這些特性外,還可以使用qobject_cast()函數來對QObject類進行動態類型轉換,這個函數的功能類似于標準C++中的dynamic_cast()函數,但它不再需要RTTI的支持。這個函數嘗試將它的參數轉換為尖括號中的類型的指針,如果是正確的類型則返回一個非零的指針,如果類型不兼容則返回0。例如: QObject *obj = new MyWidget; QWidget *widget = qobject_cast<QWidget *>(obj);

信號和槽機制是Qt的核心內容,而信號和槽機制必須依賴于元對象系統,所以它是Qt中很關鍵的內容。關于元對象系統的知識,可以在Qt中查看The Meta-Object System關鍵字。


三、對象樹與擁有權

Qt中使用對象樹(object tree)來組織和管理所有的QObject類及其子類的對象。當創建一個QObject時,如果使用了其他的對象作為其父對象(parent),那么這個QObject就會被添加到父對象的children()列表中,這樣當父對象被銷毀時,這個QObject也會被銷毀。實踐表明,這個機制非常適合于管理GUI對象。例如,一個QShortcut(鍵盤快捷鍵)對象是相應窗口的一個子對象,所以當用戶關閉了這個窗口時,這個快捷鍵也可以被銷毀。 QWidget作為能夠在屏幕上顯示的所有部件的基類,擴展了對象間的父子關系。一個子對象一般也就是一個子部件,因為它們要顯示在父部件的區域之中。例如,當關閉一個消息對話框(message box)后要銷毀它時,消息對話框中的按鈕和標簽也會被銷毀,這也正是我們所希望的,因為按鈕和標簽是消息對話框的子部件。當然,我們也可以自己來銷毀一個子對象。關于這一部分的內容,大家可以在幫助索引中查看Object Trees &Ownership關鍵字。 在前面的Qt編程中我們應該看到過很多使用new來創建一個部件,但是卻沒有使用delete來進行釋放的問題。這里再來研究一下這個問題。

新建Qt Gui應用,項目名稱為“myOwnership”,基類選擇QWidget,然后類名保持“Widget”不變。完成后向項目中添加新文件,模板選擇C++ Class,類名為“MyButton”,基類為“QPushButton”,類型信息選擇“繼承自QWidget”。添加完文件后在mybutton.h文件中添加析構函數的聲明:

~MyButton();

然后到mybutton.cpp文件中添加頭文件#include <QDebug>并定義析構函數:

MyButton::~MyButton() { ? ?qDebug() << "delete button"; }

這樣當MyButton的對象被銷毀時,就會輸出相應的信息。這里定義析構函數,只是為了更清楚的看到部件的銷毀過程,其實一般在構建新類時不需要實現析構函數。下面在widget.cpp文件中進行更改,添加頭文件:

#include?"mybutton.h" #include<QDebug>

在構造函數中添加代碼:

MyButton?*button?=?new?MyButton(this);? ??//?創建按鈕部件,指定widget為父部件 button->setText(tr("button"));

更改析構函數:

Widget::~Widget() { ? ??delete?ui;? ??qDebug() << "delete widget";}

Widget類的析構函數中默認的已經有了銷毀ui的語句,這里又添加了輸出語句。當Widget窗口被銷毀時,將輸出信息。下面運行程序,然后關閉窗口,在QtCreator的應用程序輸出欄中的輸出信息為:

delete widget delete button

可以看到,當關閉窗口后,因為該窗口是頂層窗口,所以應用程序要銷毀該窗口部件(如果不是頂層窗口,那么關閉時只是隱藏,不會被銷毀),而當窗口部件銷毀時會自動銷毀其子部件。這也就是為什么在Qt中經常只看到new操作而看不到delete操作的原因。再來看一下main.cpp文件,其中Widget對象是建立在棧上的:

Widget?w; w.show();

這樣對于對象w,在關閉程序時會被自動銷毀。而對于Widget中的部件,如果是在堆上創建(使用new操作符),那么只要指定Widget為其父窗口就可以了,也不需要進行delete操作。整個應用程序關閉時,會去銷毀w對象,而此時又會自動銷毀它的所有子部件,這些都是Qt的對象樹所完成的。

所以,對于規范的Qt程序,我們要在main()函數中將主窗口部件創建在棧上,例如“Widget w;”,而不要在堆上進行創建(使用new操作符)。對于其他窗口部件,可以使用new操作符在堆上進行創建,不過一定要指定其父部件,這樣就不需要再使用delete操作符來銷毀該對象了。

還有一種重定義父部件(reparented)的情況,例如,將一個包含其他部件的布局管理器應用到窗口上,那么該布局管理器和其中的所有部件都會自動將它們的父部件轉換為該窗口部件。在widget.cpp文件中添加頭文件#include?<QHBoxLayout>,然后在構造函數中繼續添加代碼:

MyButton?*button2?=?new?MyButton; MyButton?*button3?=?new?MyButton; QHBoxLayout?*layout?=?new?QHBoxLayout; layout->addWidget(button2); layout->addWidget(button3); setLayout(layout);? ?? ?//?在該窗口中使用布局管理器

這里創建了兩個MyButton和一個水平布局管理器,但是并沒有指定它們的父部件,現在各個部件的擁有權(ownership)不是很清楚。但是當使用布局管理器來管理這兩個按鈕,并且在窗口中使用這個布局管理器后,這兩個按鈕和水平布局管理器都將重定義父部件而成為窗口Widget的子部件。可以使用children()函數來獲取一個部件的所有子部件的列表,例如在構造函數中再添加如下代碼:

qDebug() << children();? ??//?輸出所有子部件的列表

這時大家可以運行一下程序,查看應用程序輸出欄中的信息,然后根據自己的想法更改一下程序,來進一步體會Qt中對象樹的概念。



結語


Qt中的對象樹很好地解決了父子部件的關系,對于Gui編程是十分方便的,在創建部件時我們只需要關注它的父部件,這樣就不用再考慮其銷毀問題了。下一節,我們將講解Qt中的信號和槽的內容。


涉及到的源碼:??myOwnership.rar?(2.02 KB, 下載次數: 3)?


總結

以上是生活随笔為你收集整理的[Qt教程] 第43篇 进阶(三)对象树与拥有权的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。