QWidget理論使用總結
- 一、概述
- 二、頂層 控件 和子 控件
- 三、復合控件
- 四、自定義控件和繪制
- 五、大小提示和大小策略
- 六、事件
- 七、一組函數和屬性
- 八、QWidget樣式表
- 九、透明度和雙緩沖
- 十、創建半透明窗口
一、概述
widget 是用戶界面的最小單位:它從window系統接收鼠標、鍵盤和其他事件,并在屏幕上顯示自己。每個組件都是矩形的,并且按z軸順序排列(就是窗口在屏幕里面層次的位置)。一個 控件 會被它的父 控件 和它前面的 控件 剪切。(其實就是被遮擋的意思)。
QWidget 是Qt里面其他控件的公共基類。
沒有嵌入到父窗口中的控件稱為窗口。通常,窗口有一個邊框和一個標題欄,不過也可以使用適當的窗口標志創建沒有這兩個裝飾的窗口)。在Qt中,QMainWindow 和 QDialog 的各種子類是最常見的窗口類型。
每個 控件 的構造函數都接受一到兩個標準參數:
QWidget *parent = nullptr
- QWidget *parent = nullptr 是新widget的父組件。如果它是nullptr(默認值),新 控件 將是一個窗口。如果不是,它將是parent的子元素,并受其父元素幾何形狀的限制(除非指定Qt::Window作為窗口標志)。
Qt::WindowFlags f = 0
- Qt::WindowFlags f = 0 (在可用的地方)設置窗口標志;默認值適用于幾乎所有窗口組件,但如果要獲得一個沒有窗口系統框架的窗口,則必須使用特殊的標志。
QWidget有許多成員函數,但其中一些幾乎沒有直接功能;例如,QWidget有一個font屬性,但它自己從不使用它,因為他也作為其他窗口的基類。其子類才提供了真正的功能,例如QLabel、QPushButton、QListWidget和QTabWidget等。
二、頂層 控件 和子 控件
沒有父窗口的窗口始終是一個獨立窗口(頂級窗口組件)。對于這些窗口組件,setWindowTitle() 和 setWindowIcon() 分別設置標題欄和圖標。就像下圖就能看出來是什么意思,設置窗口的圖標和標題欄。
非窗口 控件 是子控件 ,顯示在它們的父 控件 中。Qt中的大多數控件主要作為子控件使用。例如,可以將按鈕顯示為頂層窗口,但大多數人更喜歡將按鈕放在其他 控件 中,如QDialog。
上圖顯示了一個QGroupBox小 控件 用于在QGridLayout提供的布局中保存各種子小 控件 。QLabel子 控件 已被概述以表明其完整尺寸。
三、復合控件
當一個小 控件 被用作一個 容器 來分組許多子小 控件 時,它被稱為復合小 控件 。因為QWidget可以做容器來承載控件的。這些可以通過構建具有所需視覺屬性的窗口組件(例如QFrame,QGroupBox)來創建,并向其中添加子窗口組件,通常通過布局來管理。上圖使用的QGroupBox 了一個使用Qt Designer創建的復合組件。其實就是說用類似 QWidget 或者 QFrame 來作為其他控件的承載控件。其實可以理解為由父控件和子控件構成一起的控件可看成復合控件。
還可以通過繼承標準窗口小 控件 (如QWidget或QFrame)并在子類的構造函數中添加必要的布局和子窗口小 控件 來創建復合窗口小 控件 。Qt提供的許多示例都使用這種方法,Qt教程中也介紹了這種方法。
四、自定義控件和繪制
由于QWidget是QPaintDevice的子類,可以使用子類來顯示使用一系列繪制操作和QPainter類的實例組成的自定義內容。繪制就是自定義控件的一大利器,我們可以用繪制的方式繪制控件的外觀,交互的話就可以用 鼠標事件或者在自定義控件里面添加對應的響應控件也可以響應,繪制主要是影響的外觀。繪制的話也是繪制的背景,不會影響這個 QWidget內部的子控件。
這種方法與 Graphics View Framework 使用的canvas風格的方法不同,后者是由應用程序將項目添加到場景中,然后由框架自身渲染。
每個 控件 都在其 paintEvent() 函數中執行所有繪制操作。 每當控件需要重繪時,無論是由于某些外部更改還是應用程序請求重繪時,都會調用這個方法。我們需要做的就是重寫這個函數就可以啦,就行下面的時鐘例子,就用的繪制方式。
更為酷炫的,像這種的也是通過繪制的方式來制作的。
五、大小提示和大小策略
在實現新窗口組件時,幾乎總是需要重新實現 sizeHint(),為窗口組件提供一個合理的默認大小,并使用 setSizePolicy() 設置正確的大小策略。
默認情況下,沒有提供大小提示的復合 控件 將根據其子 控件 的空間需求進行調整。
size策略允許你為布局管理系統提供良好的默認行為,以便其他 控件 可以輕松地包含和管理你的 控件 。默認大小策略表明size提示表示窗口組件的首選大小,這對于許多窗口組件來說通常已經足夠了。
注意:頂級 控件 的大小被限制為桌面高度和寬度的2/3。如果這些邊界不夠用,可以手動 resize() 控件 。
六、事件
QWidget 的 事件也是非常重要的,Qt的窗口相關事件系統基本上體現在 QWidget 的 基礎函數里面,這些函數都可以讓我們自己重寫,然后擴展功能。
控件 響應通常由用戶操作引起的事件。Qt通過調用特定的事件處理程序函數和包含每個事件信息的QEvent子類實例來向 控件 傳遞事件。
如果控件只包含子 控件 ,則可能不需要實現任何事件處理程序。如果要檢測子 控件 中的鼠標點擊,則在控件的mousePressEvent() 中調用子控件的 underMouse() 函數。
Scribble示例實現了一組更廣泛的事件來處理鼠標移動、按鈕按下和窗口大小調整。
您需要為自己的控件提供行為和內容,但下面是與QWidget相關的事件的簡要概述,從最常見的開始:
事件名 | 功能 |
---|---|
paintEvent() | 每當控件需要重繪時,都會調用這個函數,每個顯示自定義內容的小控件都必須實現它。使用QPainter進行繪制只能在paintEvent()或由paintEvent()調用的函數中進行。 |
resizeEvent() | resizeEvent() 在控件被調整大小后被調用。 |
mousePressEvent() | 當鼠標指針在控件內部按下鼠標按鈕,或者控件使用grabMouse()抓取鼠標時,會調用mousePressEvent()。在不松開鼠標的情況下按下鼠標,實際上與調用grabMouse()是一樣的。 |
mouseReleaseEvent() | mouseReleaseEvent() 在鼠標按鍵松開時調用。當widget接收到相應的鼠標按下事件時,它會接收鼠標釋放事件。這意味著,如果用戶在widget內按下鼠標,然后在釋放鼠標按鈕之前將鼠標拖動到其他地方,則widget將接收release事件。但有一個例外:如果鼠標按鈕按下時出現一個彈出菜單,這個彈出菜單會立即竊取鼠標事件。 |
mouseDoubleClickEvent() | mouseDoubleClickEvent() 在用戶雙擊widget時被調用。如果用戶雙擊,widget會接收到一個鼠標按壓事件、一個鼠標釋放事件、(一個鼠標點擊事件) 、第二個鼠標按下事件、這個事件以及最后一個鼠標釋放事件。(如果在操作過程中鼠標沒有保持穩定,也可能會接收到一些鼠標移動事件。) 在第二次點擊到來之前,無法區分是點擊還是雙擊。(這就是為什么大多數GUI書籍建議雙擊是單擊的擴展,而不是觸發另一個動作的原因之一。) |
接受鍵盤輸入的控件需要重新實現以下幾個事件處理程序。
事件名 | 功能 |
---|---|
keyPressEvent() | 每當按鍵被按下時,都會調用keyPressEvent()方法,當按鍵按下時間長到自動重復時,也會調用keyPressEvent()方法。只有當Tab和Shift+Tab鍵不被焦點改變機制使用時,它們才會被傳遞給widget。要強制小控件處理這些鍵,必須重新實現QWidget::event()。 |
focusInEvent() | focusInEvent()在小控件獲得鍵盤焦點時被調用(假設您已經調用了setFocusPolicy())。表現良好的控件以一種清晰而謹慎的方式表明它們擁有鍵盤焦點。 |
focusOutEvent() | focusOutEvent()在小控件失去鍵盤焦點時被調用。 |
你可能還需要重新實現一些不太常見的事件處理程序:
事件名 | 功能 |
---|---|
mouseMoveEvent() | mouseMoveEvent()會在鼠標移動而鼠標按鈕按住不放時調用。這在拖放操作中很有用。如果調用setMouseTracking(true),即使沒有按下任何按鈕,也會得到鼠標移動事件。(參見拖放參考線。) |
keyReleaseEvent() | keyReleaseEvent()方法會在按鍵被釋放時以及按鍵被按下時(如果按鍵是自動重復的)被調用。在這種情況下,widget將在每次重復時收到一對按鍵釋放和按鍵按下事件。只有當Tab和Shift+Tab鍵不被焦點改變機制使用時,它們才會被傳遞給widget。要強制小控件處理這些鍵,必須重新實現QWidget::event()。 |
wheelEvent() | 每當用戶在widget獲得焦點時轉動鼠標滾輪時,都會調用wheelEvent()。 |
enterEvent() | enterEvent()在鼠標進入控件的屏幕空間時被調用。(這不包括組件的任何子組件擁有的屏幕空間。) |
leaveEvent() | 當鼠標離開控件的屏幕空間時,會調用leaveEvent()。如果鼠標進入一個子控件,它不會導致leaveEvent()。 |
moveEvent() | enterEvent()會在控件相對于其父控件被移動時調用。 |
closeEvent() | closeEvent()在用戶關閉控件時(或調用close()時)被調用。 |
在QEvent::Type的文檔中還描述了一些相當模糊的事件。要處理這些事件,需要直接重新實現event()。
event()的默認實現處理Tab和Shift+Tab(移動鍵盤焦點),并將大多數其他事件傳遞給上面更專門的處理程序之一。
七、一組函數和屬性
功能相關 | 相關函數 |
---|---|
窗口功能 | show(), hide(), raise(), lower(), close(). |
頂層窗口 | windowModified, windowTitle, windowIcon, isActiveWindow, activateWindow(), minimized, showMinimized(), maximized, showMaximized(), fullScreen, showFullScreen(), showNormal(). |
窗口內容 | update(), repaint(), scroll(). |
窗口幾何 | pos, x(), y(), rect, size, width(), height(), move(), resize(), sizePolicy, sizeHint(), minimumSizeHint(), updateGeometry(), layout(), frameGeometry, geometry, childrenRect, childrenRegion, adjustSize(), mapFromGlobal(), mapToGlobal(), mapFromParent(), mapToParent(), maximumSize, minimumSize, sizeIncrement, baseSize, setFixedSize() |
模式 | visible, isVisibleTo(), enabled, isEnabledTo(), modal, isWindow(), mouseTracking, updatesEnabled, visibleRegion(). |
觀感 | style(), setStyle(), styleSheet, cursor, font, palette, backgroundRole(), setBackgroundRole(), fontInfo(), fontMetrics(). |
鍵盤焦點功能 | focus, focusPolicy, setFocus(), clearFocus(), setTabOrder(), setFocusProxy(), focusNextChild(), focusPreviousChild(). |
鼠標和鍵盤抓取 | grabMouse(), releaseMouse(), grabKeyboard(), releaseKeyboard(), mouseGrabber(), keyboardGrabber(). |
事件處理程序 | event(), mousePressEvent(), mouseReleaseEvent(), mouseDoubleClickEvent(), mouseMoveEvent(), keyPressEvent(), keyReleaseEvent(), focusInEvent(), focusOutEvent(), wheelEvent(), enterEvent(), leaveEvent(), paintEvent(), moveEvent(), resizeEvent(), closeEvent(), dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(), dropEvent(), childEvent(), showEvent(), hideEvent(), customEvent(). changeEvent(), |
系統功能 | parentWidget(), window(), setParent(), winId(), find(), metric(). |
上下文菜單 | contextMenuPolicy, contextMenuEvent(), customContextMenuRequested(), actions() |
交互式幫助 | setToolTip(), setWhatsThis() |
- 窗口功能
其實就是 控制窗口的 顯示隱藏,關閉,以及窗口在屏幕里面的 Z-index 上移、下沉。 - 頂層窗口
控制窗口最大,最小化,全屏,激活、設置窗口圖標或者標題等 - 窗口內容
窗口內容的刷新,重新繪制,滾動等等。 - 窗口幾何
窗口的長寬大小、坐標位置等信息 - 模式
窗口的顯示、隱藏、使能等 - 觀感
窗口的樣式,外觀,字體、顏色等等 - 鍵盤焦點功能
就是輸入的 焦點管理 - 系統功能
獲取窗口的句柄,與Windows交互要多些
八、QWidget樣式表
除了每個平臺的標準窗口樣式外,還可以根據樣式表中指定的規則設置窗口小部件的樣式。此功能使我們能夠自定義特定部件的外觀,以向用戶提供有關其用途的視覺提示。例如,可以為一個按鈕設置特定的樣式,以表明它執行了破壞性操作。Qt提供的就是 QSS 樣式表。
QSS 其實是Qt樣式表,就是一種美化界面的方式。Qt樣式表是Qt界面的一種強大的機制,可以讓我們自定義窗口組件的外觀。Qt樣式表的概念、術語和語法很大程度上受到HTML層疊樣式表(CSS)的啟發。功能和CSS的基本一樣,大家應該也是有CSS 的基本基礎,那寫QSS就很容易的。下面就是我對QSS的相關筆記
?? Qt掃盲-QSS概述 🏤
?? Qt掃盲-QSS語法概述 ??
?? Qt Designer配置QSS交互使用 ??
?? Qt掃盲-QSS定制Qt Widget控件 🌟
?? Qt掃盲-QSS幫助手冊使用 ?
?? Qt掃盲-QSS示例代碼 🌵
九、透明度和雙緩沖
自Qt 4.0以來,QWidget自動對其繪制進行雙緩沖,因此不需要在paintEvent()中編寫雙緩沖代碼以避免閃爍。
從Qt 4.1開始,Qt::WA_ContentsPropagated部 件屬性已經被棄用。相反,只要沒有設置Qt::WA_PaintOnScreen,父部件的內容就會默認傳播到每個子部件。
我們可以編寫自定義部件來利用這一特性,方法是更新不規則區域(以創建非矩形的子部件),或者使用小于完整alpha的組件繪制顏色。下圖顯示了如何微調自定義小部件的屬性和屬性以實現不同的效果。
在上圖中,構建了一個移除區域的半透明矩形子部件,并將其添加到父部件(顯示pixmap的QLabel)。然后,設置不同的屬性和widget屬性來實現不同的效果:
- 左邊的小部件沒有其他屬性或設置小部件屬性。這個默認狀態適合大多數使用透明度、形狀不規則或者不使用不透明的畫筆覆蓋整個區域的自定義部件。
- 中心部件設置了autoFillBackground屬性。此屬性與依賴widget提供默認背景的自定義部件一起使用,這些部件不會用不透明的畫筆繪制整個區域。
- 右邊的部件設置了Qt::WA_OpaquePaintEvent部件屬性。這表示部件將用不透明的顏色覆蓋整個區域。小部件的區域最初是未初始化的,在圖中以紅色對角網格模式表示,該模式穿過覆蓋的區域。WA_OpaquePaintArea屬性對于需要快速繪制自己的專門化內容且不需要默認填充背景的部件非常有用。
要用簡單的背景顏色快速更新自定義窗口組件,如實時繪圖或繪圖窗口組件,最好定義一個合適的背景顏色(使用帶有QPalette::Window 的 setBackgroundRole()),設置 autoFillBackground 屬性,并僅在窗口組件的 paintEvent() 中實現必要的繪圖功能。
為了快速更新不斷用不透明內容覆蓋整個區域的自定義窗口組件(例如視頻流窗口組件),最好設置窗口組件的Qt::WA_OpaquePaintEvent,避免與重繪窗口組件背景相關的任何不必要的開銷。
如果窗口組件同時設置了Qt::WA_OpaquePaintEvent屬性和autoFillBackground屬性,則Qt::WA_OpaquePaintEvent屬性優先。根據您的需求,您可以選擇其中任何一個。
從Qt 4.1開始,父組件的內容也會傳播到標準Qt組件。如果父部件以非標準的方式裝飾,這可能會導致一些意想不到的結果,如下圖所示。
在不借助于子類的情況下,定制標準Qt窗口組件的繪制行為的范圍比定制窗口組件的范圍要小一些。通常,標準窗口組件的期望外觀可以通過設置其 autoFillBackground 屬性來實現。
十、創建半透明窗口
從Qt 4.5開始,可以在支持合成的窗口系統上創建具有半透明區域的窗口。
要在頂級部件中啟用此功能,請使用 setAttribute() 設置其Qt::WA_TranslucentBackground屬性,并確保其背景在希望部分透明的區域中使用非不透明顏色繪制。
平臺注意事項:
- X11:此功能依賴于支持ARGB視覺效果的X服務器和合成窗口管理器的使用。
- Window:窗口組件需要設置 Qt::FramelessWindowHint 窗 口標志,才能使半透明工作。