PyQT 入门(二)

3. 入门2: 通过Qt Designer设计应用程序

3.1. Step 1: 使用Qt Designer设计UI
Ui: demo.ui
PyQT 入门(二)_第1张图片
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:
PyQT 入门(二)_第2张图片
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()

Output:
PyQT 入门(二)_第3张图片

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:
PyQT 入门(二)_第4张图片
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()

Output:
PyQT 入门(二)_第5张图片
2) 添加自定义signal
Code:

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:
PyQT 入门(二)_第6张图片
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函数参数类型不一致。
  1. 通过pyqtConfigure()实现signal-slot关联
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 入门(三)

你可能感兴趣的:(PyQT 入门(二))