簡體   English   中英

將 PyQt5 按鈕連接到函數時如何使用 lambda

[英]How to use lambda when connecting PyQt5 buttons to functions

在我的代碼中,當單擊一個按鈕 ( self.longRunningBtn ) 時,它會連接到一個不帶參數的函數並且它工作正常。 當該函數被修改為采用額外的參數a, b, c我收到一個錯誤TypeError: argument 1 has unexpected type 'NoneType' 然后通過在調用中添加 lambda 來解決這個問題,但現在該函數似乎根本沒有運行,並且整個 GUI 凍結,即使它位於不同的線程上。 我希望能夠單擊帶有參數a, b, c self.longRunningBtn a, b, c而不會看到該錯誤並且不會凍結 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"))

返回TypeError: argument 1 has unexpected type '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"))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM