3.1. Step 1: 使用Qt Designer设计UI
Ui: demo.ui
Code:
demo.ui转python code 可以通过指令: pyuic5 demo.ui -o ui_demo.py 来实现
ui_demo.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'demo.ui'
#
# Created by: PyQt5 UI code generator 5.8.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MyWidget(object):
def setupUi(self, MyWidget):
MyWidget.setObjectName("MyWidget")
MyWidget.resize(256, 80)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MyWidget.sizePolicy().hasHeightForWidth())
MyWidget.setSizePolicy(sizePolicy)
MyWidget.setMinimumSize(QtCore.QSize(256, 80))
MyWidget.setMaximumSize(QtCore.QSize(256, 80))
self.gridLayout_2 = QtWidgets.QGridLayout(MyWidget)
self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.lineEdit = QtWidgets.QLineEdit(MyWidget)
self.lineEdit.setObjectName("lineEdit")
self.gridLayout.addWidget(self.lineEdit, 0, 0, 1, 1)
self.btnBrowse = QtWidgets.QPushButton(MyWidget)
self.btnBrowse.setObjectName("btnBrowse")
self.gridLayout.addWidget(self.btnBrowse, 0, 1, 1, 1)
self.btnExit = QtWidgets.QPushButton(MyWidget)
self.btnExit.setObjectName("btnExit")
self.gridLayout.addWidget(self.btnExit, 1, 1, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
self.retranslateUi(MyWidget)
self.btnExit.clicked.connect(MyWidget.close)
QtCore.QMetaObject.connectSlotsByName(MyWidget)
def retranslateUi(self, MyWidget):
_translate = QtCore.QCoreApplication.translate
MyWidget.setWindowTitle(_translate("MyWidget", "This is my QWidget"))
self.btnBrowse.setText(_translate("MyWidget", "&Browse"))
self.btnExit.setText(_translate("MyWidget", "&Exit"))
代码注释:
self.btnExit.clicked.connect(MyWidget.close)
btnExit按钮被clicked后会调用MyWIdget的close方法,退出。
mywidget.py
import sys
from ui_demo import *
from PyQt5.Qt import QApplication
from PyQt5.QtWidgets import QWidget
def main():
app = QApplication(sys.argv)
widget = QWidget()
mywidget = Ui_MyWidget()
mywidget.setupUi(widget)
widget.show()
return sys.exit(app.exec_())
if __name__ == '__main__':
main()
Output:
3.2. Step 2: 编写自定义class, 继承ui设计;增加自定义signal-slot函数。
import sys
from ui_demo import *
from PyQt5.Qt import QApplication
from PyQt5.QtWidgets import QWidget, QFileDialog
class MyWidget(Ui_MyWidget):
'''
MyWidget
'''
def __init__(self):
super().__init__()
def setupSigSlots(self):
self.btnBrowse.clicked.connect(self.slotBrowse)
def slotBrowse(self):
file, _ = QFileDialog.getOpenFileName(None, 'Caption', 'D:\\', '*.py', '*.*')
if file:
self.lineEdit.setText(file)
def main():
app = QApplication(sys.argv)
widget = QWidget()
mywidget = MyWidget()
mywidget.setupUi(widget)
mywidget.setupSigSlots()
widget.show()
return sys.exit(app.exec_())
if __name__ == '__main__':
main()
3.3. Step 3: 独立自主
以上示例中,MyWidget类是一个非GUI类,只继承了python的object类,而没有继续Qt的GUI类,这样需要调用mywidget.setupUi(widget)来实现GUI的呈现。
现在,我们要脱离widget对象,实现自我呈现GUI。
Code:
import sys
from ui_demo import *
from PyQt5.Qt import QApplication
from PyQt5.QtWidgets import QWidget, QFileDialog
class MyWidget(Ui_MyWidget, QWidget):
'''
MyWidget
'''
def __init__(self):
super().__init__()
self.setupUi(self)
def setupSigSlots(self):
self.btnBrowse.clicked.connect(self.slotBrowse)
def slotBrowse(self):
file, _ = QFileDialog.getOpenFileName(None, 'Caption', 'D:\\', '*.py', '*.*')
if file:
self.lineEdit.setText(file)
def main():
app = QApplication(sys.argv)
#widget = QWidget()
mywidget = MyWidget()
#mywidget.setupUi(widget)
mywidget.setupSigSlots()
mywidget.show()
#widget.show()
return sys.exit(app.exec_())
if __name__ == '__main__':
main()
注释:
MyWidget类继承了QWidget,然后在__init__中实现setupUi调用,从而完成了GUI的自我呈现。
Output:
3.4. Step4: signal & slot
1) 通过signal-slot实现dial与spinbox联动
Code:
import sys
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject
from PyQt5.QtWidgets import QDial, QSpinBox, QHBoxLayout, QDialog, QApplication
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.dial = QDial()
self.dial.setObjectName('dial')
self.dial.setNotchesVisible(True)
self.spinbox = QSpinBox()
self.spinbox.setObjectName('spinbox')
layout = QHBoxLayout()
layout.addWidget(self.dial)
layout.addWidget(self.spinbox)
self.setLayout(layout)
self.dial.valueChanged[int].connect(self.dial_valueChanged)
self.spinbox.valueChanged[int].connect(self.spinbox_valueChanged)
self.setWindowTitle("Signals and Slots")
def dial_valueChanged(self,val):
self.spinbox.setValue(val)
def spinbox_valueChanged(self,val):
self.dial.setValue(val)
def main():
app = QApplication(sys.argv)
form = Form()
form.show()
return sys.exit(app.exec_())
if __name__ == '__main__':
main()
import sys
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject
from PyQt5.QtWidgets import QDial, QSpinBox, QHBoxLayout, QDialog, QApplication
class Form(QDialog):
sigValChanged = pyqtSignal(int)
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.dial = QDial()
self.dial.setObjectName('dial')
self.dial.setNotchesVisible(True)
self.spinbox = QSpinBox()
self.spinbox.setObjectName('spinbox')
layout = QHBoxLayout()
layout.addWidget(self.dial)
layout.addWidget(self.spinbox)
self.setLayout(layout)
self.dial.valueChanged[int].connect(self.dial_valueChanged)
self.spinbox.valueChanged[int].connect(self.spinbox_valueChanged)
self.sigValChanged.connect(self.valueChanged)
self.setWindowTitle("Signals and Slots")
def dial_valueChanged(self,val):
self.spinbox.setValue(val)
self.sigValChanged.emit(val)
def spinbox_valueChanged(self,val):
self.dial.setValue(val)
def valueChanged(self, val):
print('valueChanged to:', val)
def main():
app = QApplication(sys.argv)
form = Form()
form.show()
return sys.exit(app.exec_())
if __name__ == '__main__':
main()
Output:
Consol输出:valueChanged to: 75
3) 通过pyqtSlot装饰器指定参数类型
可以通过@pyqtSlot(int)来指定参数类型为int:
@pyqtSlot(int)
def valueChanged(self, val):
print('valueChanged to:', val)
如果类型不匹配,则会出现runtime error, 我们把valueChanged的参数类型改为str:
@pyqtSlot(str)
def valueChanged(self, val):
print('valueChanged to:', val)
则会出现如下错误:
Traceback (most recent call last):
File "D:\android\workspace\Python\PyQt\chap04\signals.pyw", line 53, in <module>
main()
File "D:\android\workspace\Python\PyQt\chap04\signals.pyw", line 47, in main
form = Form()
File "D:\android\workspace\Python\PyQt\chap04\signals.pyw", line 29, in __init__
self.sigValChanged.connect(self.valueChanged)
TypeError: decorated slot has no signature compatible with Form.sigValChanged[int]
提示slot函数参数类型与signal函数参数类型不一致。
import sys
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject
from PyQt5.QtWidgets import QDial, QSpinBox, QHBoxLayout, QDialog, QApplication
class Form(QDialog):
sigValChanged = pyqtSignal(int)
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.dial = QDial()
self.dial.setObjectName('dial')
self.dial.setNotchesVisible(True)
self.spinbox = QSpinBox()
self.spinbox.setObjectName('spinbox')
layout = QHBoxLayout()
layout.addWidget(self.dial)
layout.addWidget(self.spinbox)
self.setLayout(layout)
#self.dial.valueChanged[int].connect(self.dial_valueChanged)
self.dial.pyqtConfigure(valueChanged=self.dial_valueChanged)
#self.spinbox.valueChanged[int].connect(self.spinbox_valueChanged)
self.spinbox.pyqtConfigure(valueChanged=self.spinbox_valueChanged)
self.sigValChanged.connect(self.valueChanged)
self.setWindowTitle("Signals and Slots")
def dial_valueChanged(self,val):
self.spinbox.setValue(val)
if self.sigValChanged != None:
self.sigValChanged.emit(val)
def spinbox_valueChanged(self,val):
self.dial.setValue(val)
@pyqtSlot(int)
def valueChanged(self, val):
print('valueChanged to:', val)
def main():
app = QApplication(sys.argv)
form = Form()
form.show()
return sys.exit(app.exec_())
if __name__ == '__main__':
main()
qrc文件编译为.py文件:
pyrcc5 resource_files.qrc -o resource_files_rc.py
上一篇:PyQT 入门(一)
下一篇:PyQT 入门(三)