如何在Qthread中更改Qtimer的间隔? [英] How can I change the interval of a Qtimer inside of a Qthread?

查看:319
本文介绍了如何在Qthread中更改Qtimer的间隔?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够在QThread内更改QTimer的间隔时间.这是我的代码.

I want to be able to change the interval time of a QTimer inside of a QThread. This is my code.

import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import QObject, QTimer, QThread


class Worker(QObject):
    def __init__(self):
        QObject.__init__(self)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.work)

    def start(self):
        self.timer.start(1000)

    def work(self):
        print("Hello World...")

    def set_interval(self, interval):
        self.timer.setInterval(interval)


def main():
    # Set up main window
    app = QApplication(sys.argv)
    win = QMainWindow()
    win.setFixedSize(200, 100)
    spinbox_interval = QtWidgets.QSpinBox(win)
    spinbox_interval.setMaximum(5000)
    spinbox_interval.setSingleStep(500)
    spinbox_interval.setValue(1000)

    worker = Worker()
    thread = QThread()
    worker.moveToThread(thread)
    thread.started.connect(worker.start)
    thread.start()

    def change_interval():
        value = spinbox_interval.value()
        worker.set_interval(value)

    spinbox_interval.valueChanged.connect(change_interval)

    win.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

如果在启动计时器后调用worker.setInterval(),则超时信号不再发出信号.有人可以向我解释我做错了什么吗?

If I call worker.setInterval() after starting the timer, the timeout signal no longer sends out a signal. Can someone explain to me what I'm doing wrong?

推荐答案

要了解此问题,您必须在控制台/CMD中运行以获取错误消息,从而了解原因,如果执行此操作,则会收到以下错误消息:

To understand the problem you must run in the console / CMD to get the error message and thus understand the cause, if you do this you get the following error message:

QObject::killTimer: Timers cannot be stopped from another thread
QObject::startTimer: Timers cannot be started from another thread

要了解此错误消息,您必须知道:

To understand this error message you must know that:

  • QObject不是线程安全的,因此无法从另一个线程进行修改,
  • QObject的子代与父代生活在同一线程中.

因此,作为工作线程的孩子的计时器然后作为其父线程驻留在辅助线程中,因此您不能从另一个线程中对其进行修改.在这种情况下,将在辅助线程中发送修改信息,为此,有几个选项:

So the timer being Worker's children then lives in the secondary thread as its parent, and therefore you cannot modify it from another thread. In this case it is to send modify the information in the secondary thread, and for this there are several options:

  • QMetaObject.invokeMethod(),带有pyqtSlot:

  • QMetaObject.invokeMethod() with pyqtSlot:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QSpinBox
from PyQt5.QtCore import pyqtSlot, QMetaObject, QObject, Qt, QTimer, QThread, Q_ARG


class Worker(QObject):
    def __init__(self):
        QObject.__init__(self)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.work)

    def start(self):
        self.timer.start(1000)

    def work(self):
        print("Hello World...")

    @pyqtSlot(int)
    def set_interval(self, interval):
        self.timer.setInterval(interval)


def main():
    # Set up main window
    app = QApplication(sys.argv)
    win = QMainWindow()
    win.setFixedSize(200, 100)
    spinbox_interval = QSpinBox(win)
    spinbox_interval.setMaximum(5000)
    spinbox_interval.setSingleStep(500)
    spinbox_interval.setValue(1000)

    worker = Worker()
    thread = QThread()
    worker.moveToThread(thread)
    thread.started.connect(worker.start)
    thread.start()

    def change_interval():
        value = spinbox_interval.value()
        QMetaObject.invokeMethod(
            worker, "set_interval", Qt.QueuedConnection, Q_ARG(int, value)
        )

    spinbox_interval.valueChanged.connect(change_interval)

    win.show()
    ret = app.exec_()

    QMetaObject.invokeMethod(worker.timer, "stop")
    thread.quit()
    thread.wait()
    sys.exit(ret)


if __name__ == "__main__":
    main()

  • 带有插槽的自定义信号:

  • A custom signal with slot:

    import sys
    from PyQt5.QtWidgets import QApplication, QMainWindow, QSpinBox
    from PyQt5.QtCore import pyqtSignal, pyqtSlot, QMetaObject, QObject, Qt, QTimer, QThread
    
    
    class Worker(QObject):
        updateInterval = pyqtSignal(int)
    
        def __init__(self):
            QObject.__init__(self)
            self.timer = QTimer(self)
            self.timer.timeout.connect(self.work)
    
            self.updateInterval.connect(self.set_interval)
    
        def start(self):
            self.timer.start(1000)
    
        def work(self):
            print("Hello World...")
    
        @pyqtSlot(int)
        def set_interval(self, interval):
            self.timer.setInterval(interval)
    
    
    def main():
        # Set up main window
        app = QApplication(sys.argv)
        win = QMainWindow()
        win.setFixedSize(200, 100)
        spinbox_interval = QSpinBox(win)
        spinbox_interval.setMaximum(5000)
        spinbox_interval.setSingleStep(500)
        spinbox_interval.setValue(1000)
    
        worker = Worker()
        thread = QThread()
        worker.moveToThread(thread)
        thread.started.connect(worker.start)
        thread.start()
    
        def change_interval():
            value = spinbox_interval.value()
            worker.updateInterval.emit(value)
    
        spinbox_interval.valueChanged.connect(change_interval)
    
        win.show()
        ret = app.exec_()
    
        QMetaObject.invokeMethod(worker.timer, "stop")
        thread.quit()
        thread.wait()
        sys.exit(ret)
    
    
    if __name__ == "__main__":
        main()
    

  • 自定义QEvent:

  • Custom QEvent:

    import sys
    from PyQt5.QtWidgets import QApplication, QMainWindow, QSpinBox
    from PyQt5.QtCore import QEvent, QMetaObject, QObject, Qt, QTimer, QThread
    
    
    class IntervalEvent(QEvent):
        def __init__(self, interval):
            QEvent.__init__(self, QEvent.User + 1000)
            self._interval = interval
    
        @property
        def interval(self):
            return self._interval
    
    
    class Worker(QObject):
        def __init__(self):
            QObject.__init__(self)
            self.timer = QTimer(self)
            self.timer.timeout.connect(self.work)
    
        def start(self):
            self.timer.start(1000)
    
        def work(self):
            print("Hello World...")
    
        def set_interval(self, interval):
            self.timer.setInterval(interval)
    
        def event(self, e):
            if isinstance(e, IntervalEvent):
                self.set_interval(e.interval)
            return Worker.event(self, e)
    
    
    def main():
        # Set up main window
        app = QApplication(sys.argv)
        win = QMainWindow()
        win.setFixedSize(200, 100)
        spinbox_interval = QSpinBox(win)
        spinbox_interval.setMaximum(5000)
        spinbox_interval.setSingleStep(500)
        spinbox_interval.setValue(1000)
    
        worker = Worker()
        thread = QThread()
        worker.moveToThread(thread)
        thread.started.connect(worker.start)
        thread.start()
    
        def change_interval():
            value = spinbox_interval.value()
            event = IntervalEvent(value)
            QApplication.postEvent(worker, event)
    
        spinbox_interval.valueChanged.connect(change_interval)
    
        win.show()
        ret = app.exec_()
    
        QMetaObject.invokeMethod(worker.timer, "stop")
        thread.quit()
        thread.wait()
        sys.exit(ret)
    
    
    if __name__ == "__main__":
        main()
    

  • QTimer.singleShot()functools.partial()(仅适用于PyQt5,不适用于PySide2)

  • QTimer.singleShot() with functools.partial() (only works with PyQt5, not with PySide2)

    import sys
    from functools import partial
    
    from PyQt5.QtWidgets import QApplication, QMainWindow, QSpinBox
    from PyQt5.QtCore import QMetaObject, QObject, Qt, QTimer, QThread
    
    
    class Worker(QObject):
        def __init__(self):
            QObject.__init__(self)
            self.timer = QTimer(self)
            self.timer.timeout.connect(self.work)
    
        def start(self):
            self.timer.start(1000)
    
        def work(self):
            print("Hello World...")
    
        def set_interval(self, interval):
            print(interval)
            self.timer.setInterval(interval)
    
    
    def main():
        # Set up main window
        app = QApplication(sys.argv)
        win = QMainWindow()
        win.setFixedSize(200, 100)
        spinbox_interval = QSpinBox(win)
        spinbox_interval.setMaximum(5000)
        spinbox_interval.setSingleStep(500)
        spinbox_interval.setValue(1000)
    
        worker = Worker()
        thread = QThread()
        worker.moveToThread(thread)
        thread.started.connect(worker.start)
        thread.start()
    
        def change_interval():
            value = spinbox_interval.value()
            wrapper = partial(worker.set_interval, value)
            QTimer.singleShot(0, wrapper)
    
        spinbox_interval.valueChanged.connect(change_interval)
    
        win.show()
        ret = app.exec_()
    
        QMetaObject.invokeMethod(worker.timer, "stop")
        thread.quit()
        thread.wait()
        sys.exit(ret)
    
    
    if __name__ == "__main__":
        main()
    

  • 这篇关于如何在Qthread中更改Qtimer的间隔?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆