简体   繁体   English

PyQt5 Qtimer 不启动

[英]PyQt5 Qtimer don't start

i'm stucked on a Qtimer that don't start, so the number that i need to update on the GUI is never showed.我被困在一个无法启动的 Qtimer 上,所以我需要在 GUI 上更新的数字永远不会显示。

i don't want to use a while loop inside the code because i need to change some values in real time without any problem.我不想在代码中使用 while 循环,因为我需要实时更改一些值而没有任何问题。

i really don't understand why it don't start... or better, it start, but don't run the function update_label.我真的不明白为什么它不启动......或者更好的是,它启动了,但不要运行 function update_label。

any suggestion?有什么建议吗?

Thanks a lot for your time!非常感谢您的时间!

here is my code:这是我的代码:

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        
        self.setObjectName("MainWindow")
        self.resize(1300, 768)
        self.setMinimumSize(1300,768)
        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("Bot", "Bot"))
        
        self.number = QtWidgets.QLabel(self)
        self.number .setGeometry(QtCore.QRect(1100, 10, 300, 20))
        self.number .setObjectName("number")
        
        
        self.show()
        
        
    
        
        self.threadpool = QThreadPool()
        self.updater = Updater()
        self.threadpool.start(self.updater)
        
        self.updater.update_progress.latest_number.connect(self.update_number)

    @pyqtSlot(str)
    def update_number(self, val):
        x = str(val)
        self.number.setText("Current block: " + x)  
        
  
    
class Updater(QRunnable):
    def __init__(self):
        super(Updater, self).__init__()
        self.update_progress = WorkerSignal()
        
        print("started")
        
        
    def run(self):
        self.timer = QTimer()
        self.timer.setInterval(2000)
        self.timer.timeout.connect(self.update_label)
        self.timer.start()
            
        
        
    def update_label(self):
        
        provider = configfile.provider
        number = str(nmbr.latest_numer(provider))
        self.update_progress.latest_number.emit(number)
        print("update label started")

After tyring to understand your script, I reached the conclusion that QRunnable is automatically released (or stopped) once Updater.run(self) reaches its end.在努力理解您的脚本之后,我得出的结论是,一旦Updater.run(self)到达终点, QRunnable就会自动释放(或停止)。

But this is supposed to happen , because that's why you should use a QThreadPool in the first place.但这应该会发生,因为这就是为什么您首先应该使用QThreadPool的原因。 It is supposed to recycle expired threads in the background of the application.它应该在应用程序的后台回收过期的线程。

So, as you're running a QTimer in the thread, QThreadPool thinks that Updater thread is dead, while in reality, the timer is still running on the background of a background thread.因此,当您在线程中运行QTimer时, QThreadPool认为Updater线程已死,而实际上,计时器仍在后台线程的后台运行。 So it does its job and releases Updater from the Thread pool.所以它完成了它的工作并从线程池中释放了Updater

What you must do in order to keep both the Timer and Updater alive is to manager the Updater thread's lifecycle yourself .为了保持 Timer 和Updater都处于活动状态,您必须自己管理Updater线程的生命周期。

So instead of using QThreadPool and QRunnable , you must go one level lower in terms of abstraction, and use the QThread and QObject themselves in order to control when the thread is going to be stopped.因此,不要使用QThreadPoolQRunnable ,您必须在抽象方面将 go 降低一级,并使用QThreadQObject本身来控制何时停止线程。

from PySide2 import QtWidgets, QtCore
from PySide2.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
from PySide2.QtCore import Qt, QThreadPool, QRunnable, Slot, Signal, QObject, QTimer, QThread

class WorkerSignal(QObject):
    # Changed pyqtSignal to Signal
    latest_number = Signal(str)

class Worker(QObject):
    def __init__(self):
        QObject.__init__(self)
        self.update_progress = WorkerSignal()

    def update_label(self):
        print("update label started")
        try:
            provider = configfile.provider
            number = str(nmbr.latest_numer(provider))
            self.update_progress.latest_number.emit(number)
        except:
            print("Error, but just for testing...")
            self.update_progress.latest_number.emit("0")

    def main(self):
        print('Init worker')
        self.timer = QTimer()
        self.timer.setInterval(2000)
        self.timer.timeout.connect(self.update_label)
        self.thread().finished.connect(self.timer.stop)
        self.timer.start()

class Updater(QThread):
    def __init__(self):
        QThread.__init__(self)

        self.worker = Worker()

        # Move worker to another thread, to execute in parallel
        self.worker.moveToThread(self)

        # Set which method from Worker that should excute on the other thread. 
        # In this case: Worker.main
        self.started.connect(self.worker.main)

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        QMainWindow.__init__(self, *args, **kwargs)
        
        self.setObjectName("MainWindow")
        self.resize(1300, 768)
        self.setMinimumSize(1300,768)
        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("SniperBot", "SniperBot"))
        
        self.number = QtWidgets.QLabel(self)
        self.number.setGeometry(QtCore.QRect(1100, 10, 300, 20))
        self.number.setObjectName("number")

        # I did this to see the label, as it was not attached to any
        # widget's layout on your script.
        widget = QWidget()
        layout = QVBoxLayout()
        widget.setLayout(layout)
        layout.addWidget(self.number)
        self.setCentralWidget(widget)
        self.scene = widget
        
        self.show()
        
        # Create the Updater thread.
        self.updater = Updater()

        # Connect the Worker's signal to self.update_number
        self.updater.worker.update_progress.latest_number.connect(self.update_number)

        # Start the thread
        self.updater.start()

    def closeEvent(self, evt):
        # Before exiting from the application, remember, we control now
        # the Updater Thread's lifecycle. So it's our job to stop the thread
        # and wait for it to finish properly.
        self.updater.quit()
        self.updater.wait()

        # Accept the event. Exit the application.
        evt.accept()

    # Changed pyqtSlot to Slot
    @Slot(str)
    def update_number(self, val):
        x = str(val)
        print("UPDATE NUMBER: ", x)
        self.number.setText("Current block: " + x)  

if __name__ == '__main__':
    app = QApplication()
    win = MainWindow()
    win.show()
    app.exec_()

What you can do now is follow this pattern and start implementing from here.您现在可以做的是遵循此模式并从这里开始实施。 There are many tutorials that use the moveToThread method.有很多教程使用moveToThread方法。 Just be careful to not let the thread or any object be recycled by the python's garbage collector, in order to avoid many other problems.请注意不要让线程或任何 object 被 python 的垃圾收集器回收,以避免许多其他问题。

The script is working, however I use PySide2 instead of PyQt5 .该脚本正在运行,但是我使用PySide2而不是PyQt5 So some variable and modules names may change, so just rename them when you try to run the script on your end.所以一些变量和模块的名字可能会改变,所以当你尝试运行脚本时重命名它们。


There were a few errors on Worker.update_label(self) , which is just a copied script from the old Updater.update_label(self) . Worker.update_label(self)上有一些错误,这只是从旧的Updater.update_label(self)复制的脚本。 I don't know what are the variables: configfile or nmbr as they are not initialized on your post.我不知道变量是什么: configfilenmbr ,因为它们没有在您的帖子中初始化。 So I made a try-except block to handle the error and make the script work just for testing.所以我做了一个try-except块来处理错误并使脚本仅用于测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM