pyqt5界面开发一些笔记

pyqt5界面开发一些笔记

给ui类添加信号插槽和其他功能

一般ui类通过 qtdesigner 来设计,然后用 pyuic 来讲ui文件转成py代码,此时如果在py代码中添加对应的插槽函数功能等,会存在一个问题,因为ui文件经常改,每次pyuic转换都会覆盖之前的,之前写的插槽函数等就白写了。

正确的做法是,另外写一个相同但有不同后缀名字的py文件,然后在这个新的py文件中使用类继承的方式类创建新类,在新类中填写插槽函数等功能。

如下所示:

# 1、首先用qtdesinger设计ui,得到 demo_ui.ui
# 2、新建类文件,demo_win.py
from PyQt5.QtWidgets import QMainWindow
from PyQt5.uic import loadUiType
UI_CLASS, _ = loadUiType('demo_ui.ui')
class MainApp(QMainWindow, UI_CLASS):
        def __init__(self):  # 定义构造方法
            QMainWindow.__init__(self)
            # setupUi生成ui后,就可以添加按钮事件等的功能了
            self.setupUi(self)
            self.btn.clicked.connect(self.btn_func)  # 此处给按钮添加插槽函数
        def btn_func(self):
            do_something


子窗口暂停主窗口

创建Qdialog窗口,等待Qdialog完成用户输入或确认,然后继续执行主窗口的函数,否则就会是类似非阻塞线程的工作模式了。如下所示:

class TemplateInputDailog:
    弹出输入框或确认对话框,让用户输入,阻塞主进程
    def __init__(self):
        self.dialog = QDialog()     # 注意是Qdialog,而不是QInputDialog
        self.dialog.setWindowModality(Qt.ApplicationModal)  # 阻塞主进程等待用户输入完成
        self.dialog.setWindowTitle(title)  #  设置标题
        self.layout = QFormLayout(self.dialog)  # 使用layout排版,并附着在dialog窗体中
        # 添加输入框
        self.label = QLabel(label_str)
        self.input = QLineEdit()
        self.layout.addRow(self.label, self.input)
        # 确认或取消按钮
        self.check_btn = QPushButton('确认')
        self.close_btn = QPushButton('取消')
        self.check_btn.clicked.connect(self.check_btn_func)
        self.close_btn.clicked.connect(self.close_btn_func)
        self.layout.addRow(self.check_btn, self.close_btn)
        self.dialog.exec_()  # 注意此处用exec_方法


子界面给主界面发送信号(跨界面通信)

这应该是很常见的需求了,当然也不是那么好理解的。一般来说跨进程通信可以使用队列什么的,但是在界面编程中,如果使用队列,就需要消费者对队列进行监听,此处容易造成主程序卡死?

在Qt中,正确的方法是使用信号与槽,这也是Qt的核心精华所在,使用信号与槽功能可以使得事件编程变得非常非常简单。但是信号与槽要理解起来也有点困难,特别是在Qt编程中,主要是具体写法可能会造成不工作但也不知道为什么。

关于信号与槽,简单来说就是 回调函数 。信号就是A发生了一个操作,比如点击按钮,槽函数就是回调函数,比如按钮的回调函数是关闭窗口、打开对话框等。

在Qt中有很多内置信号,比如点击按钮、点击列表元素、拖动进度条、内容改变监测等,也有很多槽函数,比如关闭窗口。

同界面信号与槽函数1

这个比较简单,直接在界面(控件)类中定义按钮的信号,在类中直接定义回调函数即可,比如下面的例子:

from PyQt5.uic import loadUiType
Ui_MainWindow, _ = loadUiType('Ui_MainWindow.ui')
class MyWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.setupUi(self)
        # 定义按钮连接的槽函数
        self.button_name.clicked.connect(self.button_callback_func)
    def button_callback_func(self):
        # 定义槽函数的内容
        pass


跨界面信号与槽

跨界面信号与槽比较难,但是掌握关键点也很简单的,那就是:

(1)信号函数需要定义成一个全局变量(或子界面可以调用的变量)

(2)且不能是主界面的self变量

(3)子界面是主界面的self属性,这样子界面才能调用主界面的信号属性

说的比较难懂,看下面的例子:

from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QWidget
from PyQt5.uic import loadUiType
# 导入用户ui文件
Ui_MainWindow, _ = loadUiType('Ui_MainWindow.ui')
class subWindow(QWidget):
    # 在子界面 subWindow 中定义信号,注意不能在 __init__ 中定义成 self.signal
    # 如果是pyside2库,则是 signal = Signal(str)
    signal = pyqtSignal(str)
    def __init__(self, parent=None):
        super(subWindow, self).__init__(parent)
        # 定义子界面的按钮事件
        self.button_name.clicked.connect(self.button_callback_func)
    def button_callback_func(self):
        """点击按钮,发射信号"""
        self.signal.emit("子界面发送信号")
class mainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(mainWindow, self).__init__(parent)
        self.setupUi(self)
        # 此处需要在主界面的 __init__ 函数中实例化子界面,将子界面当做主界面的属性来管理
        self.subwin = subWindow()
        # 实例化子界面后,就可以指定子界面的信号对应的槽函数了
        self.subwin.signal.connect(self.signal_callback_func)
    def signal_callback_func(self, param):
        # 定义槽函数,注意此函数带有一个参数 param,即信号发送过来的数据
        do_something(param)
    

pyside6中的信号与槽用法

pyside6中的信号与槽的语法会严谨一些,不过用起来也是差不多的。


from PySide6.QtCore import QStringListModel, Slot, Signal
from PySide6.QtWidgets import QMainWindow, QWidget
from PySide6.uic import loadUiType
# 导入用户ui文件
Ui_MainWindow, _ = loadUiType('Ui_MainWindow.ui')
class subWindow(QWidget):
    # 在子界面 subWindow 中定义信号,注意不能在 __init__ 中定义成 self.signal
    signal_name = Signal(str)
    def __init__(self, parent=None):
        super(subWindow, self).__init__(parent)
        # 定义子界面的按钮事件
        self.button_name.clicked.connect(self.button_callback_func)
    def button_callback_func(self):
        """点击按钮,发射信号"""
        self.signal_name.emit("子界面发送信号")
class mainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(mainWindow, self).__init__(parent)
        self.setupUi(self)
        # 此处需要在主界面的 __init__ 函数中实例化子界面,将子界面当做主界面的属性来管理
        self.subwin = subWindow()
        # 实例化子界面后,就可以指定子界面的信号对应的槽函数了
        self.subwin.signal.connect(self.signal_callback_func)