since you already used signals/slots mechanism in your program you can easily replace python thread mechanism with QThread() and make it use separate Counter() object to divide program into separate logical blocks:
# Similar to threading.thread(target=self.counter.start)
self.counterThread = QThread()
self.counter = Counter()
self.counter.moveToThread(self.counterThread)
self.counterThread.started.connect(self.counter.start)
Where the Counter() class (often named as Worker() class) is:
class Counter(QObject):
'''
Class intended to be used in a separate thread to generate numbers and send
them to another thread.
'''
newValue = pyqtSignal(str)
stopped = pyqtSignal()
def __init__(self):
QObject.__init__(self)
def start(self):
'''
Count from 0 to 99 and emit each value to the GUI thread to display.
'''
for x in range(100):
self.newValue.emit(str(x))
time.sleep(.01)
self.stopped.emit()
By using this approach you can even modify Counter() object to receive some data from the GUI on-the-fly and react accordingly.
Another minor thing is that "from package import *" was used. Usually it is considered a bad practice since you import all the contents of the package. In this case all QtCore and QtWidgets modules were imported which is ~2/3 of the PyQt5 package itself I believe))) It is more verbose but much better to use:
from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
from PyQt5.QtCore import pyqtSignal, QObject, QThread
or:
from PyQt5 import QtWidgets, QtCore
...
self.button = QtWidgets.QPushButton()
That way you and other code readers always know which object belongs to which package as well.
Here is the complete code rewritten according to those notes:
'''
https://codereview.stackexchange.com/questions/138992/simple-pyqt5-counting-gui
'''
import sys
import time
from PyQt5.QtWidgets import QMainWindow, QPushButton, QVBoxLayout, QFrame, QApplication
from PyQt5.QtCore import pyqtSignal, QObject, QThread
class Counter(QObject):
'''
Class intended to be used in a separate thread to generate numbers and send
them to another thread.
'''
newValue = pyqtSignal(str)
stopped = pyqtSignal()
def __init__(self):
QObject.__init__(self)
def start(self):
'''
Count from 0 to 99 and emit each value to the GUI thread to display.
'''
for x in range(100):
self.newValue.emit(str(x))
time.sleep(.01)
self.stopped.emit()
class Application(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
# Configuring widgets
self.button = QPushButton()
self.button.setText('99')
self.layout = QVBoxLayout()
self.layout.addWidget(self.button)
self.frame = QFrame()
self.frame.setLayout(self.layout)
self.setCentralWidget(self.frame)
# Configuring separate thread
self.counterThread = QThread()
self.counter = Counter()
self.counter.moveToThread(self.counterThread)
# Connecting signals
self.button.clicked.connect(self.startCounting)
self.counter.newValue.connect(self.button.setText)
self.counter.stopped.connect(self.counterThread.quit)
self.counterThread.started.connect(self.counter.start)
def startCounting(self):
'''
Start counting if no other counting is done.
'''
if not self.counterThread.isRunning():
self.counterThread.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Application()
window.show()
sys.exit(app.exec_())
Keep up the good work and best wishes.
pyqtSignal
instead of just setting the text directly? \$\endgroup\$