PyQt4 精彩例項分析* 例項12 基本佈局管理
本例項利用基本佈局管理(QHBoxLayout,QVBoxLayout,QGridLayout)實現一個類似QQ的使用者資料修改頁面。實現效果圖如下圖所示。
Qt提供的佈局類以及它們之間的繼承關係如下圖所示。
常用到的佈局類有QHBoxLayout,QVBoxLayout,QGridLayout 3種,分別水平排列布局,垂直排列布局和表格排列布局。Qt3中的QHBox和QVBox到Qt4以後被廢棄。佈局中最常用的方法有addWidget()和addLayout(),addWidget()方法用於在佈局中插入控制元件,addLayout()用於在佈局中插入子佈局。
下面通過例項的實現過程瞭解佈局管理的使用方法。首先通過一個示意圖瞭解此對話方塊的佈局結構,如下圖所示。
從上圖中可知,本例項共用到4個佈局管理器,分別是LeftLayout,RightLayout,BottomLayout和MainLayout。
下面是具體的實現。
# -*- coding: utf-8 -*- from PyQt4.QtGui import * from PyQt4.QtCore import * import sys QTextCodec.setCodecForTr(QTextCodec.codecForName("utf8")) class LayoutDialog(QDialog): def __init__(self,parent=None): super(LayoutDialog,self).__init__(parent) self.setWindowTitle(self.tr("使用者資訊")) label1=QLabel(self.tr("使用者名稱:")) label2=QLabel(self.tr("姓名:")) label3=QLabel(self.tr("性別:")) label4=QLabel(self.tr("部門:")) label5=QLabel(self.tr("年齡:")) otherLabel=QLabel(self.tr("備註:")) otherLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken) userLineEdit=QLineEdit() nameLineEdit=QLineEdit() sexComboBox=QComboBox() sexComboBox.insertItem(0,self.tr("男")) sexComboBox.insertItem(1,self.tr("女")) departmentTextEdit=QTextEdit() ageLineEdit=QLineEdit() labelCol=0 contentCol=1 leftLayout=QGridLayout() leftLayout.addWidget(label1,0,labelCol) leftLayout.addWidget(userLineEdit,0,contentCol) leftLayout.addWidget(label2,1,labelCol) leftLayout.addWidget(nameLineEdit,1,contentCol) leftLayout.addWidget(label3,2,labelCol) leftLayout.addWidget(sexComboBox,2,contentCol) leftLayout.addWidget(label4,3,labelCol) leftLayout.addWidget(departmentTextEdit,3,contentCol) leftLayout.addWidget(label5,4,labelCol) leftLayout.addWidget(ageLineEdit,4,contentCol) leftLayout.addWidget(otherLabel,5,labelCol,1,2) leftLayout.setColumnStretch(0,1) leftLayout.setColumnStretch(1,3) label6=QLabel(self.tr("頭像:")) iconLabel=QLabel() icon=QPixmap("image/2.jpg") iconLabel.setPixmap(icon) iconLabel.resize(icon.width(),icon.height()) iconPushButton=QPushButton(self.tr("改變")) hLayout=QHBoxLayout() hLayout.setSpacing(20) hLayout.addWidget(label6) hLayout.addWidget(iconLabel) hLayout.addWidget(iconPushButton) label7=QLabel(self.tr("個人說明:")) descTextEdit=QTextEdit() rightLayout=QVBoxLayout() rightLayout.setMargin(10) rightLayout.addLayout(hLayout) rightLayout.addWidget(label7) rightLayout.addWidget(descTextEdit) OKPushButton=QPushButton(self.tr("確定")) cancelPushButton=QPushButton(self.tr("取消")) bottomLayout=QHBoxLayout() bottomLayout.addStretch() bottomLayout.addWidget(OKPushButton) bottomLayout.addWidget(cancelPushButton) mainLayout=QGridLayout(self) mainLayout.setMargin(15) mainLayout.setSpacing(10) mainLayout.addLayout(leftLayout,0,0) mainLayout.addLayout(rightLayout,0,1) mainLayout.addLayout(bottomLayout,1,0,1,2) mainLayout.setSizeConstraint(QLayout.SetFixedSize) app=QApplication(sys.argv) dialog=LayoutDialog() dialog.show() app.exec_()
第13-26行定義對話方塊左側的控制元件。其中第19行設定控制元件的風格,setFrameStyle()是QFrame的方法,引數以或的方式設定控制元件的面板風格,由形式(QFrame.Shape)和陰影(QFrame.Shadow)兩項配合設定。其中,形狀有NoFrame,Panel,Box,HLine,VLine以及WinPanel 6種,陰影有Plain,Raised和Sunken 3種,具體的效果讀者可自行搭配試驗。
在定義程式碼中,可以不必為各個控制元件指定父視窗,使用佈局管理會自動指定佈局管理下的所有控制元件的父視窗。
第28-44行定義控制元件佈局,實現左部佈局。
第28行定義一個QGridLayout物件leftLayout,由於此佈局管理器並不是主佈局管理器,因此不用指定父視窗,最後由主佈局管理器統一指定。
QGridLayout類的addWidget()方法用來向佈局中加入需佈局的控制元件,第32-42行呼叫此方法插入需佈局的控制元件。addWidget()的函式原型如下:
addWidget (self, QWidget)
addWidget (self, QWidget, int, int, Qt.Alignment alignment = 0)
addWidget (self, QWidget, int, int, int, int, Qt.Alignment alignment = 0)
QWidget引數為需插入的控制元件物件,後面的兩個int引數為插入的行和列,再後面兩上int引數為跨度的行數和跨度的列數,alignment引數描述各控制元件的對齊方式。
第41行和42行設定兩列分別佔用的空間的比例,此處設定兩列的空間比為1:3。即使對話方塊框架大小改變了,兩列之間的寬度比依然保持不變。
第46-56行實現對話方塊右上側的頭像選擇區的佈局,此處採用一個QHBoxLayout類進行佈局管理。QHBoxLayout預設採取自左向右的方式順序排列插入的控制元件,也可通過呼叫setDirection()方法設定排列的順序,例如:
hLayout.setDirection(QBoxLayout.RightToLeft)
第53行呼叫QLayout的setSpacing()方法設定各個控制元件之間的間距為20。
第58-65行程式碼實現對話方塊右側的佈局。由一個QVBoxLayout實現佈局,QVBoxLayout預設自上而下順序排列插入的控制元件或子佈局,也可通過setDirection()方法改變排列的順序。由於右側上部的頭像選擇區已使用佈局,因此第63行呼叫addLayout()方法在佈局中插入子佈局。
第67-72行程式碼實現對話方塊下方兩個按鈕的佈局,採用QHBoxLayout實現。
第70行呼叫addStretch()方法在按鈕之前插入一個佔位符,使兩個按鈕能靠右對齊。並且在整個對話方塊的大小發生改變時,保證按鈕的大小不發生變化。合理使用addStretch()能讓介面的佈局效果增色不少。
最後實現主佈局,用一個QGridLayout實現,並在定義主佈局時指定父視窗self,也可呼叫self.setLayout(mainLayout)實現。
第75行設定對話方塊的邊距為15。
第79行插入的子佈局佔用了兩列,使用的函式方法和前面的是一樣的,也呼叫addLayout()方法,只是引數不同,原型如下:
addLayout (self, QLayout, int, int, int, int, Qt.Alignment alignment = 0)
QLayout引數為需插入的控制元件物件,後面的兩個int引數為插入的行和列,再後面兩上int引數為跨度的行數和跨度的列數,alignment引數描述各控制元件的對齊方式。
最後,第80行設定對話方塊的控制元件總是最優化顯示,並且使用者無法改變對話方塊的大小,所謂最優化顯示,即控制元件都按其sizeHint()的大小顯示。
在Qt3的佈局中,插入佔用多行或多列的方法為addMultiCellWidget()和addMultiCellLayout(),在Qt4中廢棄了這兩種方法,而是統一成addWidget()和addLayout()兩種方法。