本实例利用基本布局管理(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()两种方法。