t设计师是Qt的所见即所得的界面设计工具,通过拖拉方式设计界面,但它并不能产生任何代码。
Qt设计师使用.ui后缀的XML文件来存储界面内容。通过pyuic4命令可以编译成.py文件,.py文件的内容就和我们手写界面的类似。
当然直接使用.ui文件也是可以的,但是有两个问题,一个是效率不高,需要在运行时做动态转换创建界面;二是不方便打包发布。这里只讲最佳实践,不讲这种方式,感兴趣的可以自己研究。我后面会写文章讲解。
下面通过一个例子,讲述如何创建界面,并编译,以及如何使用信号和槽。该例子上有一个QLabel和一个QPushButton。点击按钮,修改标签的文字为“Hello PyQt4”。
环境:
OS X 10.8.2
Python2.7.3
PyQt4.9.4
创建界面
打开Qt设计师,在templates/forms中选择Widget,点击【创建】。进入设计状态,从窗口部件盒中拖出两个Vertical Spacer、一个Label,一个Push Button。如图所示:
在空白处点击右键,选择垂直布局。
双击按钮修改文字为"Say Hello",选中对象在属性编辑器中修改属性:
Label的objectName为lHello
Push Button的objectName属性为pbHello。
完成后的界面如下:
打开widget.ui,你会发现是个XML文件。
转换界面文件为python代码
通过pyuic4命令转换代码,把widget.ui转换成ui_widget.py文件。
$ pyuic4 -o ui_widget.py widget.ui
转换后代码如下:
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(400, 300)
self.verticalLayout = QtGui.QVBoxLayout(Form)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
spacerItem = QtGui.QSpacerItem(20, 98, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.lHello = QtGui.QLabel(Form)
self.lHello.setObjectName(_fromUtf8("lHello"))
self.verticalLayout.addWidget(self.lHello)
self.pbHello = QtGui.QPushButton(Form)
self.pbHello.setObjectName(_fromUtf8("pbHello"))
self.verticalLayout.addWidget(self.pbHello)
spacerItem1 = QtGui.QSpacerItem(20, 98, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.lHello.setText(QtGui.QApplication.translate("Form", "TextLabel", None, QtGui.QApplication.UnicodeUTF8))
self.pbHello.setText(QtGui.QApplication.translate("Form", "Say Hello", None, QtGui.QApplication.UnicodeUTF8))
注意到代码中self.lHello和self.pbHello变量,他们的名字是和我们前面界面设计的objectName是一一对应的。
注意
不要把业务代码写在ui_widget.py文件中,下次使用pyuic4命令的时候将会覆盖该文件,你所做的一切工作将白费。
使用转换后的界面代码
这里只介绍使用Python的多重继承方式。这种方式有个好处是代码编写方便,而且可以通过self. + objectName的方式来调用界面组件。
# -*- coding: utf-8 -*-
from PyQt4 import QtGui
from ui_widget import Ui_Form
class Widget(QtGui.QWidget, Ui_Form):
"""QtGui.QWidget和界面设计时选择的类型一致"""
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self) # Ui_Form.setupUi
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
widget = Widget()
widget.show()
sys.exit(app.exec_())
处理按钮点击事件
PyQt支持使用QtCore.pyqtSignature()装饰器来连接信号和槽,不需要通过手工连接。具体方法名为on_objectName_信号,代码如下:
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
from ui_widget import Ui_Form
class Widget(QtGui.QWidget, Ui_Form):
"""QtGui.QWidget和界面设计时选择的类型一致"""
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self) # Ui_Form.setupUi
@QtCore.pyqtSignature("")
def on_pbHello_clicked(self):
"""pbHello和界面设计时的objectName一致"""
self.lHello.setText('Hello PyQt4') # lHello和界面设计的objectName一致
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
widget = Widget()
widget.show()
sys.exit(app.exec_())