将信号发射到线程

发布于 2025-02-07 12:30:26 字数 2532 浏览 1 评论 0原文

我正在使用PYQT5创建图形用户界面。 我想在执行一定过程时将信号发送到运行线程以更改参数。

我创建了一个简单的代码来演示我打算实现的目标。 下面的代码生成带有两个按钮的基本GUI。 按下第一个按钮时,创建并启动了一个线程,该线程每秒都会打印一个字符串。按下第二个按钮时,将修改显示的字符串并用另一个字符串替换。

我的问题是字符串永远不会更改,我不确定为什么。

import sys
from time import sleep

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

from PyQt5.QtCore import QObject, QThread, pyqtSignal

class Worker(QObject):
    finished = pyqtSignal()

    def __init__(self, parent=None):
        super(Worker, self).__init__()
        self.mutex = QMutex()
        self.stringToDisplay = 'Holà'

    def update(newStringToDisplay):
        self.mutex.lock()
        self.stringToDisplay = newStringToDisplay
        self.mutex.unlock()

    def run(self):
        """Long-running task."""
        while 1:
            sleep(1)
            self.mutex.lock()
            print(self.stringToDisplay)
            self.mutex.unlock()

        self.finished.emit()


class Window(QMainWindow):

    updateSignal = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()

    def setupUi(self):
        self.setWindowTitle("GUI")
        self.resize(300, 150)
        self.button2runThread = QPushButton('Click to start the thread', self)
        self.button2runThread.clicked.connect(self.runThread)

        self.button2updateParams = QPushButton('Click to update parameter in the running thread', self)
        self.button2updateParams.clicked.connect(self.updateThread)

        layout = QVBoxLayout()
        layout.addWidget(self.button2runThread)
        layout.addWidget(self.button2updateParams)
        
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        self.centralWidget.setLayout(layout)

    def updateThread(self):
        self.updateSignal.emit('My new string')

    def runThread(self):
        self.thread = QThread()
        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.updateSignal.connect(self.worker.update)

        self.thread.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec())

I'm creating a graphical user interface with PyQt5.
I want to send a signal to a running thread to change parameters while it is carrying out a certain process.

I created a simple code to demonstrate what I intend to achieve.
The code below generates a basic GUI with two push buttons.
When the first button is pressed, a thread is created and started, which prints a string every second. When the second button is pressed, the displayed string is modified and replaced with another string.

My issue is that the string is never changed, and I'm not sure why.

import sys
from time import sleep

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

from PyQt5.QtCore import QObject, QThread, pyqtSignal

class Worker(QObject):
    finished = pyqtSignal()

    def __init__(self, parent=None):
        super(Worker, self).__init__()
        self.mutex = QMutex()
        self.stringToDisplay = 'Holà'

    def update(newStringToDisplay):
        self.mutex.lock()
        self.stringToDisplay = newStringToDisplay
        self.mutex.unlock()

    def run(self):
        """Long-running task."""
        while 1:
            sleep(1)
            self.mutex.lock()
            print(self.stringToDisplay)
            self.mutex.unlock()

        self.finished.emit()


class Window(QMainWindow):

    updateSignal = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()

    def setupUi(self):
        self.setWindowTitle("GUI")
        self.resize(300, 150)
        self.button2runThread = QPushButton('Click to start the thread', self)
        self.button2runThread.clicked.connect(self.runThread)

        self.button2updateParams = QPushButton('Click to update parameter in the running thread', self)
        self.button2updateParams.clicked.connect(self.updateThread)

        layout = QVBoxLayout()
        layout.addWidget(self.button2runThread)
        layout.addWidget(self.button2updateParams)
        
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        self.centralWidget.setLayout(layout)

    def updateThread(self):
        self.updateSignal.emit('My new string')

    def runThread(self):
        self.thread = QThread()
        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.updateSignal.connect(self.worker.update)

        self.thread.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec())

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

清晨说晚安 2025-02-14 12:30:26

我能够指出这个问题。
在将工人移至线程之前,我将信号连接起来。

这是导致问题的代码的一部分:

    self.thread = QThread()
    self.worker = Worker()

    self.worker.moveToThread(self.thread) # 1
    # ...
    # ...
    self.updateSignal.connect(self.worker.update) # must be called before 1

以及完整的代码:

import sys
from time import sleep

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

from PyQt5.QtCore import QObject, QThread, pyqtSignal

class Worker(QObject):
    finished = pyqtSignal()

    def __init__(self, parent=None):
        super(Worker, self).__init__()
        self.mutex = QMutex()
        self.stringToDisplay = 'Holà'

    def update(self, newStringToDisplay):
        self.mutex.lock()
        self.stringToDisplay = newStringToDisplay
        self.mutex.unlock()


    def run(self):
        """Long-running task."""
        while 1:
            sleep(1)
            self.mutex.lock()
            print(self.stringToDisplay)
            self.mutex.unlock()

        self.finished.emit()


class Window(QMainWindow):

    updateSignal = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()

    def setupUi(self):
        self.setWindowTitle("GUI")
        self.resize(300, 150)
        self.button2runThread = QPushButton('Click to start the thread', self)
        self.button2runThread.clicked.connect(self.runThread)

        self.button2updateParams = QPushButton('Click to update parameter in the running thread', self)
        self.button2updateParams.clicked.connect(self.updateThread)

        layout = QVBoxLayout()
        layout.addWidget(self.button2runThread)
        layout.addWidget(self.button2updateParams)
        
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        self.centralWidget.setLayout(layout)

    
    def updateThread(self):
        self.updateSignal.emit('My new string')
    def runThread(self):
        self.thread = QThread()
        self.worker = Worker()

        self.updateSignal.connect(self.worker.update)

        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.thread.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec())

I was able to pinpoint the issue.
I connected the signal before moving the Worker to the thread.

Here's the part of code that was causing the issue:

    self.thread = QThread()
    self.worker = Worker()

    self.worker.moveToThread(self.thread) # 1
    # ...
    # ...
    self.updateSignal.connect(self.worker.update) # must be called before 1

and the complete code:

import sys
from time import sleep

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

from PyQt5.QtCore import QObject, QThread, pyqtSignal

class Worker(QObject):
    finished = pyqtSignal()

    def __init__(self, parent=None):
        super(Worker, self).__init__()
        self.mutex = QMutex()
        self.stringToDisplay = 'Holà'

    def update(self, newStringToDisplay):
        self.mutex.lock()
        self.stringToDisplay = newStringToDisplay
        self.mutex.unlock()


    def run(self):
        """Long-running task."""
        while 1:
            sleep(1)
            self.mutex.lock()
            print(self.stringToDisplay)
            self.mutex.unlock()

        self.finished.emit()


class Window(QMainWindow):

    updateSignal = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()

    def setupUi(self):
        self.setWindowTitle("GUI")
        self.resize(300, 150)
        self.button2runThread = QPushButton('Click to start the thread', self)
        self.button2runThread.clicked.connect(self.runThread)

        self.button2updateParams = QPushButton('Click to update parameter in the running thread', self)
        self.button2updateParams.clicked.connect(self.updateThread)

        layout = QVBoxLayout()
        layout.addWidget(self.button2runThread)
        layout.addWidget(self.button2updateParams)
        
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        self.centralWidget.setLayout(layout)

    
    def updateThread(self):
        self.updateSignal.emit('My new string')
    def runThread(self):
        self.thread = QThread()
        self.worker = Worker()

        self.updateSignal.connect(self.worker.update)

        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.thread.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Window()
    win.show()
    sys.exit(app.exec())
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文