PyQt5 display variable from Thread to LCD
-
Hi, thanks for your hint.
I understand the logic you pointed out, but I know so little PyQt that I don't know how to implement what you suggested.I managed to solve half of the problem. The signal for the value of "i" works, for the checkbox it only works with the method I commented out. When I insert it in the "run" method, I get the error: "TypeError: run() missing 1 required positional argument: 'b'". I don't know how to address it
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sat Aug 11 15:48:57 2018 """ import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, QProgressBar, QVBoxLayout, QApplication, QCheckBox ) from PyQt5.QtCore import QThread, pyqtSignal import time class WorkerThread(QThread): signal_i=pyqtSignal( int, name='Signal_i') ### 1) declare the signal def __init__(self, parent=None): QThread.__init__(self) #super(WorkerThread, self).__init__(parent) def run(self, b): if b == 0: print ("non checked") else: print("checked") x = 10 for i in range(x): time.sleep(1) #print(i) self.signal_i.emit(i) ### 2) emitt the signal class Example(QWidget): def __init__(self): super().__init__() self.initUI() self.wt=WorkerThread() # This is the thread object self.wt.start() # Connect the signal from the thread to the finished method self.wt.signal_i.connect(self.slot_method) ### 3) connect to the slot def initUI(self): cb = QCheckBox("enable countdown") self.lcd = QLCDNumber(self) pro = QProgressBar(self) sld = QSlider(Qt.Horizontal, self) vbox = QVBoxLayout() vbox.addWidget(cb) vbox.addWidget(self.lcd) vbox.addWidget(pro) vbox.addWidget(sld) self.setLayout(vbox) self.setGeometry(300, 300, 250, 150) self.setWindowTitle('Signal and slot') self.show() sld.valueChanged.connect(pro.setValue)#link the slider to the progress bar #cb.stateChanged.connect(self.buttonchange) cb.stateChanged.connect(WorkerThread.run) def slot_method(self, i): ### 4) this is the slot that receive the signal #print("i:",+i) self.lcd.display(i) # def buttonchange(self, b): # if b == 0: # print ("non checked") # else: # print("checked") if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())
-
Why are you trying to connect the checkbox to the run method ? That's not the goal of that method at all.
-
Why are you trying to connect the checkbox to the run method ? That's not the goal of that method at all.
@SGaist I want to use that check box to exit the while loop I will have in the Thread (reading data from the serial port, and sending it to the lcd).
Otherwise when I close the GUI the Thread keeps running. -
You can use QThread:: requestInterruption and in your run method isInterruptionRequested.
But the check box is a wrong GUI idea, you should rather use a normal button.
-
This post is deleted!
-
The idea of the checkbox is to ebnable/disable the serial data read when the checkbox is selected/unselected.
It works with the method cbchange. Is this what you meant?If I connect the interruption to the pushbutton, the gui hangs at boot
btn.clicked.connect(self.wt.requestInterruption()) #THIS HANGS
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sat Aug 11 15:48:57 2018 @author: gio """ import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, QProgressBar, QVBoxLayout, QApplication, QCheckBox, QPushButton) from PyQt5.QtCore import QThread, pyqtSignal import time class WorkerThread(QThread): mysignal_i=pyqtSignal( int, name='Signal_i') ### 1) declare the signal def __init__(self, parent=None): QThread.__init__(self) #super(WorkerThread, self).__init__(parent) def run(self): x = 10 for i in range(x): time.sleep(1) print(i) self.mysignal_i.emit(i) ### 2) emitt the signal if self.isInterruptionRequested(): print ("exit loop") break class Example(QWidget): def __init__(self): super().__init__() self.initUI() self.wt=WorkerThread() # This is the thread object #self.wt.start() # Connect the signal from the thread to the slot_method self.wt.mysignal_i.connect(self.slot_method) ### 3) connect to the slot def initUI(self): cb = QCheckBox("enable countdown") cb.setChecked(False) self.lcd = QLCDNumber(self) pro = QProgressBar(self) sld = QSlider(Qt.Horizontal, self) btn = QPushButton(self) btn.setText('stop thread') vbox = QVBoxLayout() vbox.addWidget(cb) vbox.addWidget(btn) vbox.addWidget(self.lcd) vbox.addWidget(pro) vbox.addWidget(sld) self.setLayout(vbox) self.setGeometry(300, 300, 300, 300) self.setWindowTitle('Signal and slot') self.show() sld.valueChanged.connect(pro.setValue)#link the slider to the progress bar cb.stateChanged.connect(self.cbchange) #cb.stateChanged.connect(WorkerThread.run) #btn.clicked.connect(self.wt.requestInterruption()) #THIS HANGS def slot_method(self, i): ### 4) this is the slot that receive the signal #print("i:",+i) self.lcd.display(i) def cbchange(self, b): if b == 0: print ("non checked") self.wt.requestInterruption() else: print("checked") self.wt.start() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())
-
Hi
Does break in python do the same as return in c++ ?void long_task() { forever { if ( QThread::currentThread()->isInterruptionRequested() ) { return; } } }
If its break like in c++ , you only ask it to skip for loop but not bail out of run()
(i think/assume) -
Hi
Does break in python do the same as return in c++ ?void long_task() { forever { if ( QThread::currentThread()->isInterruptionRequested() ) { return; } } }
If its break like in c++ , you only ask it to skip for loop but not bail out of run()
(i think/assume) -
The idea of the checkbox is to ebnable/disable the serial data read when the checkbox is selected/unselected.
It works with the method cbchange. Is this what you meant?If I connect the interruption to the pushbutton, the gui hangs at boot
btn.clicked.connect(self.wt.requestInterruption()) #THIS HANGS
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sat Aug 11 15:48:57 2018 @author: gio """ import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider, QProgressBar, QVBoxLayout, QApplication, QCheckBox, QPushButton) from PyQt5.QtCore import QThread, pyqtSignal import time class WorkerThread(QThread): mysignal_i=pyqtSignal( int, name='Signal_i') ### 1) declare the signal def __init__(self, parent=None): QThread.__init__(self) #super(WorkerThread, self).__init__(parent) def run(self): x = 10 for i in range(x): time.sleep(1) print(i) self.mysignal_i.emit(i) ### 2) emitt the signal if self.isInterruptionRequested(): print ("exit loop") break class Example(QWidget): def __init__(self): super().__init__() self.initUI() self.wt=WorkerThread() # This is the thread object #self.wt.start() # Connect the signal from the thread to the slot_method self.wt.mysignal_i.connect(self.slot_method) ### 3) connect to the slot def initUI(self): cb = QCheckBox("enable countdown") cb.setChecked(False) self.lcd = QLCDNumber(self) pro = QProgressBar(self) sld = QSlider(Qt.Horizontal, self) btn = QPushButton(self) btn.setText('stop thread') vbox = QVBoxLayout() vbox.addWidget(cb) vbox.addWidget(btn) vbox.addWidget(self.lcd) vbox.addWidget(pro) vbox.addWidget(sld) self.setLayout(vbox) self.setGeometry(300, 300, 300, 300) self.setWindowTitle('Signal and slot') self.show() sld.valueChanged.connect(pro.setValue)#link the slider to the progress bar cb.stateChanged.connect(self.cbchange) #cb.stateChanged.connect(WorkerThread.run) #btn.clicked.connect(self.wt.requestInterruption()) #THIS HANGS def slot_method(self, i): ### 4) this is the slot that receive the signal #print("i:",+i) self.lcd.display(i) def cbchange(self, b): if b == 0: print ("non checked") self.wt.requestInterruption() else: print("checked") self.wt.start() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())
btn.clicked.connect(self.wt.requestInterruption()) #THIS HANGS
You're misunderstanding how you're intended to use
connect
in PyQt. It's the same principle as in C++, just different syntax. The point is, you mustconnect
to the function ("pointer"), you must not call the function in the argument toconnect
.So all your PyQt
connect
s need to look like:btn.clicked.connect(self.wt.requestInterruption)
Note that
requestInterruption
does not have a()
at the end of it! Do you follow the vital difference? It's also the same principle as why you have to writebtn.clicked.connect
and notbtn.clicked().connect
.