python - 将 PyQt5 按钮连接到函数时如何使用 lambda

标签 python python-3.x pyqt pyqt5

在我的代码中,当单击按钮(self.longRunningBtn)时,它会连接到一个不带参数的函数,并且工作正常。当该函数被修改为采用额外参数a,b,c时,我收到错误TypeError:参数1具有意外类型'NoneType'。然后通过将 lambda 添加到调用中来修复此问题,但现在该函数似乎根本不运行,并且整个 GUI 卡住,即使它位于不同的线程上。我希望能够单击带有参数 a, b, cself.longRunningBtn,而不会看到该错误,也不会卡住 GUI。

没有参数的原始代码,完美运行:

from PyQt5.QtCore import QObject, QThread, pyqtSignal
import sys
from time import sleep

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QMainWindow,
    QPushButton,
    QVBoxLayout,
    QWidget,
)

class Worker(QObject):
    finished = pyqtSignal()
    progress = pyqtSignal(str)

    def run(self):
        for i in range(5):
            sleep(1)
            self.progress.emit(f"{i+1}")
        self.finished.emit()


class Window(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.clicksCount = 0
        self.setupUi()

    def setupUi(self):
        self.setWindowTitle("Freezing GUI")
        self.resize(300, 150)
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        # Create and connect widgets
        self.clicksLabel = QLabel("Counting: 0 clicks", self)
        self.clicksLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self.stepLabel = QLabel("Long-Running Step: 0")
        self.stepLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self.countBtn = QPushButton("Click me!", self)
        self.countBtn.clicked.connect(self.countClicks)
        self.longRunningBtn = QPushButton("Long-Running Task!", self)
        self.longRunningBtn.clicked.connect(self.runLongTask)
        # Set the layout
        layout = QVBoxLayout()
        layout.addWidget(self.clicksLabel)
        layout.addWidget(self.countBtn)
        layout.addStretch()
        layout.addWidget(self.stepLabel)
        layout.addWidget(self.longRunningBtn)
        self.centralWidget.setLayout(layout)

    def countClicks(self):
        self.clicksCount += 1
        self.clicksLabel.setText(f"Counting: {self.clicksCount} clicks")

    def reportProgress(self, n):
        self.stepLabel.setText(f"Long-Running Step: {n}")

    def runLongTask(self):
        # Step 2: Create a QThread object
        self.thread = QThread()
        # Step 3: Create a worker object
        self.worker = Worker()
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)
        self.worker.progress.connect(self.reportProgress)
        # Step 6: Start the thread
        self.thread.start()

        # Final resets
        self.longRunningBtn.setEnabled(False)
        self.thread.finished.connect(
            lambda: self.longRunningBtn.setEnabled(True)
        )
        self.thread.finished.connect(
            lambda: self.stepLabel.setText("Long-Running Step: 0")
        )

app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

添加参数的代码:

    def run(self, a, b, c):
        for i in range(5):
            sleep(1)
            self.progress.emit(f"{i+1} {a} {b} {c}")
        self.finished.emit()

        self.thread.started.connect(self.worker.run("alpha", "beta", "charlie"))

返回类型错误:参数 1 具有意外类型“NoneType”

修复类型错误:

        self.thread.started.connect(lambda: self.worker.run("alpha", "beta", "charlie"))

但是现在 GUI 卡住了,我看不到该函数正在执行的任何操作,我希望它的功能与原始代码完全相同,但附加了 a, b, c标签的末尾也是如此。

最佳答案

问题在于,最终 lambda 相当于直接在主线程中调用 run() 方法,而不是在接收线程中发出信号以执行该方法。

一种可能的解决方案是使用 functools.partial:

from functools import partial
self.thread.started.connect(partial(self.worker.run, "alpha", "beta", "charlie"))

关于python - 将 PyQt5 按钮连接到函数时如何使用 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68519653/

相关文章:

pyqt - QPlainTextEdit 对于大字符串消耗大量内存

python - 使用 itemChange() 限制 QGraphicsItem

python - sklearn.mixture.GMM(高斯混合模型)的问题

python - 如何使用 pymc3 指定伯努利分布的大小?

Python - 通过 Selenium 获取文本框输入数据

python - 读取多个txt文件,然后将每个文件保存为xlsx文件,每个文件具有相同的标题

python - 在用户数据中将 powershell 脚本发送到 Windows ec2

python - 正则表达式忽略负向后查找和匹配之间的所有内容

python-3.x - 从 pandastable 获取索引号

python - QPainters 同步背后的机制