Reputation: 795
I am a writing a GUI based application using the PyQT framework which connects to a device, sends commands, reads the corresponding data and displays this in real time to a table, graph widget and to a file.
Once the run button is clicked it starts a thread which sends the external device commands according to a procedure table and emits signals with the data to various methods to change the GUI.
When the run button is clicked it executes the following lines:
worker = Worker(self.runProcedure)
worker.signals.updateResults.connect(self.updateResultsTable)
worker.signals.writeResults.connect(self.writeResultsFile)
worker.signals.finished.connect(self.procedure_complete)
self.threadpool.start(worker)
within the runProcedure commands are sent to the device from the procedure table and the data read from the device is put into a list 'hfData' using code similar to that listed below:
while float(currentForceReading) <= float(target) and stopAlarm == 0:
ts = dt.now().timestamp()
hfData = (connection.readline()).split()
updateResults_callback.emit(ts, hfData) #method to update results table and graphs
writeResults_callback.emit(ts, hfData) #method to write results to a file
One of the options in the application is to hold for a period of time where it continues collecting data from the device without sending new commands.
I am looking for a way to continue taking measurements whilst in this hold time and continue updating the GUI.
I have tried to implement the following code, however this while loop blocks the GUI from updating:
stepHoldTime = float(procedureModel.data(procedureModel.index(row,4), Qt.DisplayRole))
if(stepHoldTime != 0):
endTime = time.monotonic() + stepHoldTime
while(time.monotonic() < endTime):
ts = dt.now().timestamp()
hfData = (connection.readline()).split()
updateResults_callback.emit(ts,hfData)
Is there a correct way to implement this functionality?
Upvotes: 1
Views: 783
Reputation: 497
You can start your "reader" from a separate thread
class YourUi(QtWidgets.QMainWindow):
update_data = QtCore.pyqtSignal(str)
def __init__(self):
super(YourUi, self).__init__()
self.update_data.connect(self.do_update_data)
t = threading.Thread(target=self.update_worker, args=(self.update_data,), daemon=True)
t.start()
@staticmethod
def update_worker(signal):
connection = create_conncetion()
while True:
hfData = (connection.readline()).split()
signal.emit(hfData)
time.sleep(0.1)
def do_update_data(self, hf_data):
# access GUI elemetns from main thread to prevent freezing
self.some_qt_label.setText(str(hf_data))
Upvotes: 0
Reputation: 142651
Instead of while
-loop you could run QTimer
which will execute code every few milliseconds.
It is minimal example which shows how to run function every 1000ms and update time in label.
from PyQt5.QtWidgets import QApplication, QLabel
from PyQt5.QtCore import QTimer, QDateTime
class Window(QLabel):
def __init__(self, parent=None):
super().__init__(parent)
self.showTime()
help(QTimer)
self.timer = QTimer()
self.timer.timeout.connect(self.showTime)
self.timer.start(1000)
def showTime(self):
text = QDateTime.currentDateTime().toString('yyyy-MM-dd hh:mm:ss')
self.setText(text)
if __name__ == '__main__':
app = QApplication([])
win = Window()
win.show()
app.exec()
But your problem can be more complex and it may need more complex solution. You may have to show minimal working code which we could run and see problem - and test some ideas to resolve problem.
Upvotes: 1