Worker class used in GUI is nolonger compatible to Qtimer
-
@SGaist , Here I made some changes, so plot get updated but some errors also come too:
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot #import time from PyQt5 import QtWidgets, QtCore, QtTest from pyqtgraph import PlotWidget, plot import pyqtgraph as pg import sys import os from random import randint class Worker(QObject): finished = pyqtSignal() intReady = pyqtSignal(int, name="intReady") def __init__(self): super().__init__() self.randNum = 0 @pyqtSlot() def procCounter(self): # #for i in range(1, 100): self.randNum = int(randint(0, 50)) self.intReady.emit(self.randNum) print("randNum:", self.randNum) timer.sleep(1000) #self.timer = QtCore.QTimer() #self.timer.sleep(1000) #QtTest.QTest.qWait(1) self.finished.emit() class MainWindow(QtWidgets.QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.timer = QtCore.QTimer() self.timer.setInterval(1000) self.newData = 0 self.obj = Worker() # no parent! self.thread = QThread() # no parent! self.obj.moveToThread(self.thread) self.obj.intReady.connect(self.getSignal) self.obj.finished.connect(self.thread.quit) self.thread.started.connect(self.obj.procCounter) self.thread.start() self.graphWidget = pg.PlotWidget() self.setCentralWidget(self.graphWidget) self.y = [randint(0, 50) for _ in range(50)] self.data_line = self.graphWidget.plot(self.y) self.timer.timeout.connect(self.obj.procCounter) # recent change is here self.timer.timeout.connect(self.update_plot_data) self.timer.start() @pyqtSlot(int) def getSignal(self, i): self.newData = i # get a new random value. print("getSignal:",i) def update_plot_data(self): self.y = self.y[1:] # Remove the first print("update_plot_data:",self.newData) self.y.append(self.newData) # Add a new random value. self.data_line.setData(self.y) # Update the data. worker = Worker() app = QtWidgets.QApplication(sys.argv) w = MainWindow() w.show() sys.exit(app.exec_())
Traceback (most recent call last):
File "D:\AppZ\Pycharm2025Proj\QtPort\WorkerPyGraph_1.py", line 23, in procCounter
timer.sleep(1000)
^^^^^
NameError: name 'timer' is not defined. Did you mean: 'iter'How I could make a synchronized Qtimer and emitting recent data in a manageable way?
-
@ocien said in Worker class used in GUI is nolonger compatible to Qtimer:
NameError: name 'timer' is not defined. Did you mean: 'iter'
I'm not sure whether this is the best way to do whatever it is you want (no
qDebug()
s/print()
s to show what is arriving in what undesired order), but if you do want to use this it is purely Python. So you need toimport
whatever Python module gives you sometimer
object you can callsleep()
on, nothing to do with Qt.How I could make a synchronized Qtimer and emitting recent data in a manageable way?
"Synchronized" to what? And what is a "manageable way"? If you have data arriving or generated in a thread then either you can raise a signal immediately when you receive it (e.g. if you generate it or it's external and produces some kind of "interrupt" or "callback" when new data arrives) or you can have a timer which "polls" for new data intermittently. In either case you can either raise a signal for each new data point individually or you can accumulate/buffer new data into a list/array and emit a single signal with a number of new data points when a certain time has
pastpassed or the number of points exceeds some threshold. -
@JonB said in Worker class used in GUI is nolonger compatible to Qtimer:
@ocien said in Worker class used in GUI is nolonger compatible to Qtimer:
NameError: name 'timer' is not defined. Did you mean: 'iter'
I'm not sure whether this is the best way to do whatever it is you want (no
qDebug()
s/print()
s to show what is arriving in what undesired order), but if you do want to use this it is purely Python. So you need toimport
whatever Python module gives you sometimer
object you can callsleep()
on, nothing to do with Qt.How I could make a synchronized Qtimer and emitting recent data in a manageable way?
"Synchronized" to what? And what is a "manageable way"? If you have data arriving or generated in a thread then either you can raise a signal immediately when you receive it (e.g. if you generate it or it's external and produces some kind of "interrupt" or "callback" when new data arrives) or you can have a timer which "polls" for new data intermittently. In either case you can either raise a signal for each new data point individually or you can accumulate/buffer new data into a list/array and emit a single signal with a number of new data points when a certain time has past or the number of points exceeds some threshold.
@JonB, Exactly what I need. In the Worker thread new data should be accumulated and passed to the pyqtgraph. But I don't know how for a certain time or a defined number of data do that using signal/slot approach. Not to know whether use a "broadcast signal", using a single instance of the class for that signal and use it in any sender or receiver instance or just take another path to. Is it possible let me know using a short code?
-
@JonB The print statement has been.
To show again:getSignal: 46
update_plot_data: 46
randNum: 39
getSignal: 39
Traceback (most recent call last):
File "D:\AppZ\Pycharm2025Proj\QtPort\WorkerPyGraph_1.py", line 23, in procCounter
timer.sleep(1000)
^^^^^
NameError: name 'timer' is not defined. Did you mean: 'iter'? -
@ocien said in Worker class used in GUI is nolonger compatible to Qtimer:
NameError: name 'timer' is not defined. Did you mean: 'iter'?
Are you intending to fix this?
Other than that I don't see what is wrong with the output, perhaps you would care to explain?
-
@JonB No intending. When the interval for emitting Qtimer get triggered faster for example 1ms, then inconsistency becomes observable, as you can see:
randNum: 3
update_plot_data: 50
getSignal: 37
randNum: 22
getSignal: 3
update_plot_data: 3
getSignal: 22
randNum: 50
update_plot_data: 22
getSignal: 50
randNum: 39
update_plot_data: 50
getSignal: 39
randNum: 11
update_plot_data: 39
It seems to me this way of signal/slot coding to plot real-time data, is not a systematic or precise common way to do it. I need to make emitting number and plotting it in a consistent way. Do you have any suggestion to make things work in terms of signal/slot approach? Or just by data down sampling should I keep going? If you were in my shoes how did you do it? -
@ocien
Looking at your code, which has bits commented out, am I to understand you have one timer in the main thread ticking at around 1ms and a separate delay (somehow) of 1ms in a thread, they exchange information (a random number), and you think these two separate millisecond timers (plus any thread switching) should be so perfectly in sync that you can rely on one ticking (generate data) followed by the other (plot data) ticking? -
@ocien 1ms might be too fast for signal/slot to sync. It may not make sense to update your GUI every 1ms. And your CPU will be very busy as well. How about adding a filter(500ms) to show your data. Other data can be cached in case you want to see more.