Qt QWidget 類簡介--Qt 類簡介專題(三)

一、詳細描述

QWidget類是所有用戶界面對象的基類。通俗的來講,Qt基本上所有的UI類都是由QWidget繼承出來的,而QWidget繼承QObject,
大家可以查閱Qt source 即可發現一些微妙的寫法,如這篇文章有詳細介紹:Qt 庫對象數據的聲明和使用

窗口層次

窗口部件是用戶界面的一個原子:它從窗口系統接收鼠標、鍵盤和其它事件,並且在屏幕上繪製自己的表現。每一個窗口部件都是矩形,並且它們按Z軸順序排列的。一個窗口部件可以被它的父窗口部件或者它前面的窗口部件蓋住一部分。

QDialog是最普通的頂級窗口。不被嵌入到一個父窗口部件的窗口部件被叫做頂級窗口部件。通常情況下,頂級窗口部件是有框架和標題欄的窗口(儘管如果使用了一定的窗口部件標記,創建頂級窗口部件時也可能沒有這些裝飾。)在Qt中,QMainWindow和和不同的QDialog的子類是最普通的頂級窗口。一個沒有父窗口部件的窗口部件一直是頂級窗口部件。非頂級窗口部件是子窗口部件。它們是它們的父窗口部件中的子窗口。你通常不能在視覺角度從它們的父窗口部件中辨別一個子窗口部件。在Qt中的絕大多數其它窗口部件僅僅作爲子窗口部件纔是有用的。(當然把一個按鈕作爲或者叫做頂級窗口部件也是可能的,但絕大多數人喜歡把他們的按鈕放到其它按鈕當中,比如 QDialog。)

QWidget有很多成員函數,但是它們中的一些有少量的直接功能:例如,QWidget有一個字體屬性,但是它自己從來不用。有很多繼承它的子類提供了實際的功能,比如QPushButton、QListBox和QTabDialog等等。

每一個窗口部件構造函數接受一個或兩個標準參數:

1. QWidget *parent = 0是新窗口部件的父窗口部件。如果爲0(默認),新的窗口部件將是一個頂級窗口部件。如果不是,它將會使parent的一個孩子,並且被parent的幾何形狀所強迫(除非你指定WType_TopLevel作爲窗口部件標記)。
2. WFlags f = 0(在可用的情況下)設置窗口部件標記,默認設置對於幾乎所有窗口部件都是適用的,但是,舉例來說,一個沒有窗口系統框架的頂級窗口部件,你必須使用特定的標記。

二、Top-Level 屬性以及孩子構件

A widget without a parent widget is always an independent window (top-level widget). For these widgets,
一個沒有父構件的構件通常是top-level 屬性的窗口。對於這類構件,setWindowTitle() 和 setWindowIcon() 都是有效的。

三、QWidget事件簡介

基本事件

paintEvent() – 只要窗口部件需要被重繪就被調用。每個要顯示輸出的窗口部件必須實現它並且不在paintEvent()之外在屏幕上繪製是明智的。

* resizeEvent() – 當窗口部件被重新定義大小時被調用。

* mousePressEvent() – 當鼠標鍵被按下時被調用。有六個鼠標相關事件,但是鼠標按下和鼠標釋放事件是到目前爲止最重要的。當鼠標在窗口部件內或者當它使用grabMouse()來捕獲鼠標時,它接收鼠標按下事件。

* mouseReleaseEvent() – 當鼠標鍵被釋放時被調用。當窗口部件已經接收相應的鼠標按下事件時,它接收鼠標釋放事件。這也就是說如果用戶在你的窗口部件內按下鼠標,然後拖着鼠標到其它某個地方,然後釋放,你的窗口部件接收這個釋放事件。這裏有一個例外:如果出現在彈出菜單中,當鼠標鍵被按下時,這個彈出菜單立即會偷掉這個鼠標事件。

* mouseDoubleClickEvent() – 和它看起來也許不太一樣。如果用戶雙擊,窗口部件接收一個鼠標按下事件(如果他們沒有拿牢鼠標,也許會出現一個或兩個鼠標移動事件)、一個鼠標釋放事件並且最終是這個事件。直到你看到第二次點擊是否到來之前,不能從一個雙擊中辨別一個點擊。(這是爲什麼絕大多數圖形用戶界面圖書建議雙擊是單擊的一個擴展,而不是一個不同行爲的觸發的一個原因。)

如果你的窗口部件僅僅包含子窗口部件,你也許不需要實現任何一個事件處理器。如果你想檢測在子窗口部件中的鼠標點擊,請在父窗口部件的mousePressEvent()中調用子窗口部件的hasMouse()函數。

接收鍵盤的窗口部件需要重新實現一些更多的事件處理器:

* keyPressEvent() – 只要鍵被按下和當鍵已經被按下足夠長的時間可以自動重複了就被調用。注意如果Tab和Shift+Tab鍵被用在焦點變換機制中,它們僅僅被傳遞給窗口部件。爲了強迫那些鍵被你的窗口部件處理,你必須重新實現QWidget::event()。

* focusInEvent() – 當窗口部件獲得鍵盤焦點(假設你已經調用setFocusPolicy())時被調用。寫得好的窗口部件意味着它們能按照一種清晰但謹慎的方式來獲得鍵盤焦點。

* focusOutEvent() – 當窗口部件失去鍵盤焦點時被調用。

一些窗口部件也許需要實現一些不太普通的事件處理器:

* mouseMoveEvent() – 只要當鼠標鍵被按下時鼠標移動就會被調用。舉例來說,對於拖動,這個很有用。如果你調用setMouseTracking(TRUE),儘管沒有鼠標鍵被按下,你也會獲得鼠標移動事件。(注意這個使用鼠標跟蹤的應用程序在低下的X連接下不是很有用。)(也可以參考拖放信息。)

* keyReleaseEvent() – 只要鍵被釋放和當如果這個鍵是自動重複的並且被按下一段時間時就被調用。在這種情況下窗口部件接收一個鍵釋放事件並且對於每一個重複立即有一個鍵按下事件。注意如果Tab和Shift+Tab鍵被用在焦點變換機制中,它們僅僅被傳遞給窗口部件。爲了強迫那些鍵被你的窗口部件處理,你必須重新實現QWidget::event()。

* wheelEvent() — 當窗口部件擁有焦點時,只要用戶轉動鼠標滾輪就被調用。

* enterEvent() – 當鼠標進入這個窗口部件屏幕空間時被調用。(這不包括被這個窗口部件的子窗口部件所擁有的屏幕空間。)

* leaveEvent() – 當鼠標離開這個窗口部件的屏幕空間時被調用。

* moveEvent() – 當窗口部件相對於它的父窗口部件已經被移動時被調用。

closeEvent() – 當用戶關閉窗口部件時(或這當close()被調用時)被調用。

這裏還有一些不太明顯的事件。它們在qevent.h中被列出並且你需要重新實現event()來處理它們。event()的默認實現處理Tab和Shift+Tab(移動鍵盤焦點)並且其它絕大多數事件給上面提到的一個或更多的特定處理器。

四、Window flag標識

關於QWidget 的flag 的介紹: enum Qt::WindowType flags Qt::WindowFlags 這兩個參數參閱官方文檔。

Qt 的 WindowFlags 有很多,實際使用時,若不關心窗口層次的話,大可不比太關心這個。比如說在Window 上做應用開發,大可只關注:Qt::Dialog,Qt::Tool,Qt::Window 即可。但若是做嵌入式開發就得好好看看這個屬性,整理好這部分屬性,有利於窗口管理。

五、着重介紹幾個重要成員函數

bool QWidget::close () [slot]

關閉這個窗口部件。如果窗口部件被關閉,返回真,否則返回假。首先它發送給這個窗口部件一個QCloseEvent。如果它接收這個關閉事件,它就被隱藏了。QWidget::closeEvent()的默認實現是接收這個關閉事件。當最後一個可視的頂級窗口部件被關閉,QApplication::lastWindowClosed()信號被髮射。
注意窗口的enum Qt::WidgetAttribute 屬性,窗口默認屬性是Qt::WA_MacOpaqueSizeGrip,設置上這個屬性意味着窗口調用close()只銷毀了UI想關,QWidget內還有很多內存空間沒有釋放,需調用delete 銷燬QWidget 。若需要在調用close時一併銷燬窗口可以給窗口設置Qt::WA_DeleteOnClose屬性。

bool QWidget::event ( QEvent * e ) [虛 保護]

這是主事件處理器,它處理事件e。你可以在子類中被重新實現整個函數,但是我們建議你使用一個特定的事件處理器來替代它。
事件首先把事件傳遞給所有已經被安裝的事件過濾器。如果沒有過濾器中途截取這個事件,它調用一個特定的事件處理器。
鍵按下和釋放事件被處理得和其它事件不同。event()檢查Tab和Shift+Tab並且試圖適當地移動焦點。如果沒有窗口部件被焦點移入(或者鍵按下不是Tab或Shift+Tab),event()調用keyPressEvent()。
如果它能夠把一個事件傳遞給沒個東西,這個函數就返回真,否則如果沒有任何東西想要這個事件,返回假。
也可以參考closeEvent()、focusInEvent()、focusOutEvent()、enterEvent()、keyPressEvent()、keyReleaseEvent()、leaveEvent()、mouseDoubleClickEvent()、mouseMoveEvent()、mousePressEvent()、 mouseReleaseEvent()、moveEvent()、paintEvent()、resizeEvent()、QObject::event()和QObject::timerEvent()。

void QWidget::paintEvent ( QPaintEvent * ) [虛 保護]

這個事件處理器可以在子類中被重新實現來接收繪製事件。
繪製事件就是重新繪製這個窗口部件的所有部分的一個請求。它可以是repaint()或update()的結果,或者因爲這個窗口部件原來被變暗並且現在已經不再被覆蓋了,或者其它很多原因。
很多窗口部件在當它們被請求時,它們很簡單地重新繪製整個界面,但是一些比較慢的窗口部件需要通過僅僅繪製被請求的區域QPaintEvent::region()進行優化。這個速度優化不會改變結果,在事件處理過程中,繪製僅僅發生在被改變的區域中。例如,QListView和QCanvas就是這樣做的。
Qt也試圖通過把多個繪製事件合併爲一個來加快繪製速度。當update()被調用幾次或者窗口系統發送幾次繪製事件,Qt把它們合併爲一個比較大區域(請參考QRegion::unite())的一個事件中。repaint()不允許這樣優化,所以只要可能我們建議使用update()。
當繪製事件發生,更新區域通常被擦除,所以你正在這個窗口部件的背景上繪製。這裏有一些例外並且QPaintEvent::erased()告訴你這個窗口部件是否被擦除。
背景可以通過使用setBackgroundMode()、setPaletteBackgroundColor()或setBackgroundPixmap()來設置。setBackgroundMode()的文檔詳細描述了背景,我們建議你去讀一下。

void QWidget::raise () [槽]

把這個窗口部件升高到它的父窗口部件的棧的頂部。
如果在屏幕上有與這個窗口部件重疊的兄弟,這個窗口部件將在它後來的這些兄弟之前變的可視了。
也可以參考lower()和stackUnder()。

void QWidget::repaint ( int x, int y, int w, int h, bool erase = TRUE ) [槽]

通過立即調用paintEvent()來直接重新繪製窗口部件,除非更新是失效的或者窗口部件被隱藏。

如果erase爲真,QtpaintEvent()調用之前擦除區域(x,y,w,h)。

如果w是負數,它被width()-x替換,並且如果h是負數,它被height()-y替換。

如果你需要立即重新繪製,我們建議使用repaint(),比如在動畫期間。在絕大多數情況下,update()更好,因爲它允許Qt來優化速度並且防止閃爍。

警告:如果你在一個函數中調用repaint(),而它自己又被paintEvent()調用,你也許會看到無線循環。update()函數從來不會產生循環。

也可以參考update()、paintEvent()、updatesEnabled和erase()。

發佈了1 篇原創文章 · 獲贊 31 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章