一、概述
QDockWidget類提供了一個可以停靠在QMainWindow中或作為桌面上的頂級窗口浮動的部件。停靠窗口(Dock windows)是放置在QMainWindow主窗口中央窗口部件(Central widget)周圍的次要窗口,如下圖中央部件周圍的白色區域,這塊區域老猿稱為停靠區域。
根據停靠窗口的屬性設置,停靠窗口可以在停靠區域內移動,移動到新區域並由最終用戶確定是否浮動。
QDockWidget對象由一個標題欄和內容區域組成。標題欄顯示浮動窗口標題、浮動按鈕()和關閉按鈕。根據QDockWidget的設置,這兩個按鈕可能被禁用或根本不顯示。
QDockWidget的內容區域,實際上是一個它包含的子部件,浮動窗口展示的內容即該子部件的內容,該子部件必須是QWidget或其派生類。
二、QDockWidget的重要屬性及關聯信號
2.1、Designer中QDockWidget的屬性
在Designer中,QDockWidge有如下屬性:
2.2、屬性及關聯信號介紹
2.2.1、floating屬性
floating屬性表示QDockWidget對象是否浮動在主窗口之上,如果為True表示浮動停靠部件作為漂浮在其父QMainWindow的“頂部”使用獨立窗口展現,為False則停靠在在QMainWindow中。缺省為True,可通過方法isFloating()、setFloating(bool
floating)來訪問該屬性,當此屬性改變時,會發射 topLevelChanged(bool floating) 信號,信號簽名表示QDockWidget對象現狀是否浮動在主窗口之上
2.2.2、features屬性
features屬性用於設置浮動部件的特征,其類型為枚舉類型 QDockWidget.DockWidgetFeatures,特征包括浮動窗是否可關閉(DockWidgetClosable)、是否可移動(DockWidgetMovable)、是否可浮動(DockWidgetFloatable)、是否將標題欄展示在窗口左邊成豎直標題欄(DockWidgetVerticalTitleBar)。除了這幾個值之外,該特征類型在Designer中還有如下取值:
- AllDockWidgetFeatures:表示同時設置了DockWidgetClosable、DockWidgetMovable、DockWidgetFloatable這三個特征,但不一定設置了DockWidgetVerticalTitleBar特征,但不建議使用這個值,因為Qt或PyQt可能會增加其他特征值時,AllDockWidgetFeatures包括的特征范圍可能會增加
- DockWidgetFeatureMask:表示同時設置了DockWidgetClosable、DockWidgetMovable、DockWidgetFloatable、DockWidgetVerticalTitleBar這四個特征,這個DockWidgetFeatureMask值僅在Designer中使用,選擇這個特征則自動勾選上述四個特征,但在類中無此枚舉值,即代碼不識別該值;
- NoDockWidgetFeatures:表示不設置任何特征,在Designer中選擇此值自動去掉其他特征,由於此值對應數值為0,代碼中如果使用此值與其他值組合,則此值將失效,以其他值為准
- Reserved:這個值在Designer中選擇后,將會勾選所有除NoDockWidgetFeatures之外的特征值,但該值在代碼中無效。
features屬性缺省為 DockWidgetClosable, DockWidgetMovable和DockWidgetFloatable的組合,可通過方法features() 和setFeatures(DockWidgetFeatures features)訪問該屬性。
當features屬性修改時,會發射featuresChanged(QDockWidget.DockWidgetFeatures features)信號。
注意:
- 當floating為True,而features屬性未設置為可浮動(DockWidgetFloatable)時,浮動窗是浮動狀態,但一旦停靠后就不能通過手工操作將其再浮動起來
2.2.3、allowedAreas屬性
allowedAreas屬性用於控制停靠部件在QMainWindow的停靠區域中可停靠的范圍,其類型為枚舉類型Qt.DockWidgetArea或其值的組合,分別控制可以停靠在主窗口停靠區域的左邊(LeftDockWidgetArea)、右邊(RightDockWidgetArea)、頂部(TopDockWidgetArea)、底部(BottomDockWidgetArea)、所有區域(AllDockWidgetAreas)和不能停靠(NoDockWidgetArea)。
allowedAreas屬性缺省值為AllDockWidgetAreas,即所有區域都可以停靠,可以通過allowedAreas()和setAllowedAreas(Qt.DockWidgetAreas areas)來訪問該屬性。
allowedAreas屬性發生變更時,QDockWidget會發射allowedAreasChanged(Qt.DockWidgetAreas allowedAreas)信號。
注意:
當allowedAreas設置為不能停靠(NoDockWidgetArea),經驗證測試:
- 當Designer中docked屬性設置為True時,此時通過鼠標拖拽停靠窗在停靠區域移動不能將停靠處自動停靠,但可以雙擊停靠處標題欄實現按Designer中的屬性dockWidgetArea指定位置停靠。如果設置了該停靠窗是可浮動的,停靠后還可以浮動起來
- 當Designer中docked屬性設置為False時,該停靠窗不但拖拽不能停靠,鼠標雙擊標題欄也不能停靠,而是關閉了該停靠窗
2.2.4、dockWidgetArea和docked屬性
dockWidgetArea和docked屬性這兩個屬性在Designer中有設置,dockWidgetArea表示部件的初始停靠位置,取值范圍和allowedAreas相同,docked為布爾值,表示是否啟用停靠功能,但這兩個屬性QDockWidget都沒有,實際上是用於控制調用QMainWindow的addDockWidget方法,當docked為True時,Designer生成的代碼就會調用QMainWindow的addDockWidget方法,addDockWidget第一個參數即為Designer屬性的dockWidgetArea,當docked為False時,Designer生成的代碼就不會調用QMainWindow的addDockWidget方法。
注意當docked為True時:
- 當allowedAreas設置為不能停靠(NoDockWidgetArea)時,無論dockWidgetArea設置為何值,設置后在Designer中都會自動恢復為上次allowedAreas不為不能停靠(NoDockWidgetArea)時dockWidgetArea設定的值;
- 當allowedAreas設置為AllDockWidgetAreas所有區域都可以停靠時,如果此時設置dockWidgetArea為NoDockWidgetArea、AllDockWidgetAreas、DockWidgetFeatureMask三個中的任意一個時,Designer會將allowedAreas自動修改為最近設置的LeftDockWidgetArea、RightDockWidgetArea、TopDockWidgetArea、BottomDockWidgetArea中的一個,即allowedAreas不允許設置為NoDockWidgetArea、AllDockWidgetAreas、DockWidgetFeatureMask,強行設置會自動修訂到設置前的值
三、QDockWidget的其他重要方法
除了與屬性相關的方法外,QDockWidget還有幾個比較重要的方法。
3.1、isAreaAllowed方法
isAreaAllowed方法用於判斷QMainWindow的某個停靠區域是否允許停靠,調用語法如下:
bool isAreaAllowed(Qt.DockWidgetArea area)
3.2、setTitleBarWidget方法
setTitleBarWidget方法用於給停靠窗口設置個性化的標題欄,調用語法如下:
setTitleBarWidget(QWidget widget)
說明:
- widget參數可以是任意一個QWidget 或其派生類對象,如果傳None,則將原來通過setTitleBarWidget設置的部件取消了,使用缺省的窗口標題代替
- 如果設置了一個有效的QWidget 或其派生類對象作為標題欄,在浮動時不會使用本機窗口裝飾(包括關閉按鈕),而是使用參數部件作為標題
- 如果無法直接刪除浮動窗口的標題欄,可以使用QWidget()不帶參數方式構建一個QWidget對象實現相同的效果
- 使用titleBarWidget()方法可以返回該停靠窗口使用的標題欄部件。
示例代碼:
self.robertFontColorDock = QtWidgets.QDockWidget('機器人發言字體顏色',self)
colorButton = QtWidgets.QPushButton('設置機器人文字顏色', self.robertFontColorDock)
self.robertFontColorDock.setWidget(colorButton)
self.robertFontColorDock.setFeatures(QtWidgets.QDockWidget.NoDockWidgetFeatures|QtWidgets.QDockWidget.DockWidgetFloatable)
self.robertFontColorDock.setTitleBarWidget(configWin(self))
3.3、widget和setWidget方法
在概述部分介紹了,QDockWidget對象由一個標題欄和內容區域組成。QDockWidget的內容區域,實際上是一個它包含的子部件,浮動窗口展示的內容即該子部件的內容,該子部件必須是QWidget或其派生類。方法widget和setWidget就是用於訪問QDockWidget的內容區域對應的子部件。調用語法如下:
setWidget(QWidget widget)
QWidget widget()
注意:
- 如果QDockWidget已經可見后再調用setWidget設置內容部件,則必須調用內容部件的show()方法才能看到該部件的內容
- 官方文檔說,在調用setWidget方法前,參數widget對應部件必須設置了布局,否則該widget對應部件不可見,但老猿測試未設置布局也沒有問題。
3.4、toggleViewAction方法
toggleViewAction方法返回一個動作對象,該動作對象通過點擊后可以切換停靠窗口的可見狀態,即該動作是一個對停靠部件窗口顯示或關閉的開關,如果將該動作加到菜單上,對應菜單欄的文字即為停靠窗口的title文字,這樣就可以在菜單上點擊對應菜單項進行停靠窗口的關閉和顯示,這個關閉和顯示的狀態在QMainWindow的快捷菜單中就有這樣的功能。下圖是QMainWindow的停靠窗口開關狀態快捷菜單以及將部分停靠窗口(字體設置、機器人發言字體顏色、本機輸入發言字體顏色)對應開關動作加到菜單欄的一個案例截圖:
上圖中有2個停靠窗口是關閉的,如果所有停靠窗全部顯示則如下效果:
上圖中黃色標記的標簽選項欄對應三個停靠窗。
示例代碼
a = dock.toggleViewAction()
m = self.menuBar()
m.addAction(a)
四、QDockWidget的信號
除了前面介紹屬性的時候介紹的信號allowedAreasChanged、featuresChanged、topLevelChanged外,QDockWidget還有2個信號:dockLocationChanged、visibilityChanged。
dockLocationChanged信號在QDockWidget停靠位置因手工拖拽或代碼執行導致停靠位置發生變化時發射,包括移動到不同停靠區域或同一停靠區域的不同位置都會發射該信號。信號語法:dockLocationChanged(Qt.DockWidgetArea area)
visibilityChanged信號在QDockWidget可見狀態發生變化時發射,這種可見狀態發生變化包括顯示或隱藏窗口以及QDockWidget對象停靠在選項卡區域時QDockWidget對象對應選項被選中或去選中時。信號語法:visibilityChanged(bool visible)
五、QMainWindow與QDockWidget相關的操作方法以及信號
5.1、引言
QDockWidget除了放在QMainWindow窗口內外,也可以放在其他類型的窗體如QWidget窗口內,但QMainWindow提供了與QDockWidget配套的特性如停靠區域,而其他窗口沒有配套特性,QDockWidget在其他窗口中也可以浮動,但拖拽時無法自動停靠,只能通過鼠標雙擊標題欄回到原始位置。
QMainWindow與QDockWidget相關的特性處理停靠區域的支持外,還提供了與停靠窗口相關的:
- 三個屬性:animated、dockNestingEnabled、dockOptions
- 八個方法:addDockWidget、dockWidgetArea、removeDockWidget、resizeDocks、restoreDockWidget、splitDockWidget、tabifiedDockWidgets、tabifyDockWidget
- 一個信號:tabifiedDockWidgetActivated
其中三個屬性已經在《第十一章、Designer中主窗口QMainWindow類》進行了介紹,在此不重復介紹。
5.2、addDockWidget方法
QMainWindow的addDockWidget方法用於將對應停靠窗增加到指定區域,調用語法如下:
- addDockWidget(Qt.DockWidgetArea area, QDockWidget dockwidget)
- addDockWidget(Qt.DockWidgetArea area, QDockWidget dockwidget, Qt.Orientation orientation)
參數area用於指定QDockWidget對象的初始停靠區域,orientation確認標題欄是位於頂部水平方向,還是位於左邊豎直方向。
經老猿驗證發現:
- 如果addDockWidget的floating屬性是True,則停靠窗會漂浮在主窗口上面,但當雙擊停靠窗標題欄時就會將該停靠窗停靠到參數area指定區域;
- addDockWidget的area參數不是總會起作用,要具體看看QDockWidget對象的大小以及當前主窗口的其他QDockWidget對象的排列情況,如一個比較大的浮動窗是不能放置在左邊或右邊區域,只能在頂部和底部區域;
- 如果一個QDockWidget對象未調用addDockWidget添加到主窗口中,則在主窗口的快捷菜單中無法看到該QDockWidget對象,也不能雙擊鼠標將該停靠窗由浮動改為駐留狀態;
4.addDockWidget可以重復調用,后續調用將改變前面調用的效果,即該方法不但可以將浮動窗口增加到主窗口對應浮動區域中,而且還可以用來改變浮動窗的浮動位置和標題欄方向 。
5.3、resizeDocks
resizeDocks用於將QMainWindow的多個停靠窗的大小進行調整,調用語法如下:
resizeDocks( Iterable[QDockWidget], Iterable[int], Qt.Orientation)
參數說明:
- Iterable[QDockWidget]:需要調整的多個停靠窗對象組成的迭代類型如列表
- Iterable[int]:每個停靠窗需要調整的寬度或高度
- Qt.Orientation:調整的是寬度還是高度,如果為Qt.Horizontal,調整寬度,否則調整高度
注意:
- 大小的調整受最小和最大大小的約束
- 大小調整不會影響主窗口的大小
- 如果空間有限的情況下,調整時根據各個停靠窗口的相對大小占比進行可以利用空間的調整
5.4、tabifyDockWidget
主窗口的tabifyDockWidget方法用於將主窗口的兩個停靠窗口創建一個選項卡式的停靠區域。調用語法:
tabifyDockWidget(QDockWidget first, QDockWidget second)
該方法將將second停靠窗移動到first停靠窗的頂部,在主窗口中創建一個選項卡式停靠區域。如圖:
上圖熒光筆標記部分為選項卡,藍色標記部分為停靠窗的內容區域,二者加起來就是一個選項卡式停靠區域,兩個停靠窗可以點擊下面的選項卡切換。
5.5、splitDockWidget
主窗口的splitDockWidget方法用於將一個停靠窗占據的空間分割成兩部分,原有停靠窗放置在第一部分的區域,另一個停靠窗放置在第二部分的區域。調用語法:
splitDockWidget( QDockWidget first, QDockWidget second, Qt.Orientation orientation)
說明:
- orientation:指定分割方向,是水平分隔還是垂直分隔,如果水平分隔,則這兩個停靠窗水平方向並列,first在左second在右,如果是垂直分隔,則兩個停靠窗上下排列,first在上second在下
- 如果第一個停靠窗已經是選項卡化停靠窗,則第二個停靠窗將作為新選項卡添加,而不是作為第一個的鄰居,這是因為單個選項卡只能包含一個停靠部件,此時splitDockWidget的效果與tabifyDockWidget效果相同
- splitDockWidget實際使用時更多的是用於排列相關停靠窗口使用,也即對停靠窗口通過代碼進行排列調整
案例:
要將ui設計的一個如下垂直布局的主窗口界面:
上面ui中用了三個停靠窗,從上到下分別為d3、d2、d1。如果將它們排列成一個如下的界面:
代碼如下:
self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.d1)
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.d2)
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.d3)
如果要將其設計成一個如下運行的界面:
代碼如下:
self.addDockWidget(QtCore.Qt.TopDockWidgetArea, self.d1)
#self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.d2)
#self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.d3)
self.splitDockWidget(self.d1, self.d2,Qt.Vertical)
self.splitDockWidget(self.d2,self.d3,Qt.Horizontal)
注意:上面代碼中注釋的語句與不注釋效果一樣。
上面兩種不同的界面效果,第一個因為沒有采用分隔排列,但d2、d3分別放置在左邊和右邊,由於布局的緣故,占了下面所有的空間,而第二種方式采用了分割,d3分割了d2的空間,因此二者沒有占滿整個主窗口的空間。
其實上面兩個例子還不能完整體現splitDockWidget的作用,因為停靠窗少了點,如果停靠窗很多,排列更復雜的排列,就能發揮splitDockWidget的功用。
5.6、其他方法簡介
QMainWindow的其他4個與QDockWidget相關的方法dockWidgetArea、removeDockWidget、 restoreDockWidget、tabifiedDockWidgets功能非常簡單:
- Qt.DockWidgetArea dockWidgetArea(QDockWidget dockwidget)
用於返回dockwidget停靠窗的停靠區,如果dockwidget未加到主窗口中,則返回Qt.NoDockWidgetArea。 - removeDockWidget(QDockWidget dockwidget)
用於將主窗口中的停靠窗dockwidget移除並隱藏它,但dockwidget對象並未釋放,還可以繼續使用 - bool restoreDockWidget(QDockWidget dockwidget)
將dockwidget恢復成初始創建狀態,成功返回True,否則返回False。 - list[QDockWidget] tabifiedDockWidgets(QDockWidget dockwidget)
返回與參數dockwidget指定停靠窗一起成選項卡式排列的所有停靠窗列表。
5.7、tabifiedDockWidgetActivated信號
tabifiedDockWidgetActivated信號為主窗口中的選項卡式排列的停靠窗被選中激活時發射,被激活的停靠窗為信號簽名參數。語法如下:
QMainWindow.tabifiedDockWidgetActivated(QDockWidget dockWidget)
六、小結
本章節詳細介紹了QDockWidget的屬性、方法、信號以及主窗口與QDockWidget相關的屬性、方法和信號,由於主窗口提供了對停靠窗口豐富的支撐能力,才使得通過主窗口可以構建友好的用戶界面。