最近因为开发编辑器用到了Qt这个跨平台GUI框架,实际开发时使用了PyQt。PyQt结合了Qt强大的跨平台功能以及Python易于编写的特性。这里从实际使用层面介绍下这两周来的PyQt使用心得。

使用Qt Designer

GUI编程最烦人的一点在于界面代码的编写。直接在代码中进行界面编程特别繁琐且难以维护。如果将界面实现与逻辑代码分离,无疑能极大改善编程体验。PyQt安装之后可以找到Qt Designer这个工具,在Qt Designer中可以进行界面编辑,其导出的文件可以被代码直接使用。

将Qt Designer导出文件转化为Python代码

pyuic4 -o window.py window.ui

在实际开发的时候并不一定需要做如上转化,这个转化的好处在于可以通过生成的代码来帮助熟悉控件的使用。

Python代码中直接读取.ui文件

在实际使用中,直接在代码中加载.ui文件是更合适的选择。如此,则界面与逻辑就可以进行一定程度的分离,避免在代码中陷入界面编写的细节。

# -*- encoding:utf-8 -*-

from PyQt4 import QtGui, uic


class CustomDialog(QtGui.QDialog):

    def __init__(self, cb):
        super(InputIdDialog, self).__init__()
        uic.loadUi("ui/custom_dialog.ui", self)
        self.cb = cb
        self.setWindowTitle(u"对话框")

事件响应与处理

除了界面实现之外,事件处理机制也是GUI框架必需的组成部分。在PyQt中,事件通过"signal"进行触发处理。这里不探究其内部实现,从使用层面来看与其它GUI框架无大不同。

button.clicked.connect(handle_clicked)

def handle_clicked():
    pass

上述代码片段描述的是针对按钮的点击响应处理,PyQt里将事件与响应函数通过connect方法绑定到一起。不同控件定义了多种不同signal,这些预定义的signal会在控件执行操作时进行触发。

自定义signal

PyQt支持自定义signal,其使用方法也极为简单,这里借用个例子,

class Communicate(QtCore.QObject):
    closeApp = QtCore.pyqtSignal()

class Example(QtGui.QMainWindow):

    def __init__(self):
        super(Example, self).__init__()
        self.initUI()

    def initUI(self):      
        self.c = Communicate()
        self.c.closeApp.connect(self.close)       
        self.setGeometry(300, 300, 290, 150)
        self.setWindowTitle('Emit signal')
        self.show()

    def mousePressEvent(self, event):
        self.c.closeApp.emit()

继承自QObject的类都可以自定义signal,通过emit进行触发、connect进行绑定。上述代码中还可以看到,可以进一步重载底层的mousePressEvent之类函数来自定义操作行为处理逻辑。

控件与布局

明白了上述两个大问题后,剩下的就是具体的细节了,比如PyQt中默认的控件与布局管理有哪些。结合Qt Designer可以快速浏览支持的控件布局,以及它们的各项属性。

遇到的坑

signal的绑定操作需要在主线程中执行,在其它线程中执行操作貌似不会生效。