I have a small program that does something, but i want to "switch modes", for now i press a key and an input prompts on the console, but to make it easier i want to make a window with pyqt6, the problem is that the window blocks or halts the main loop while it's open, i tried with threading/multiprocessing but i can't make it work.
import threading
from queue import Queue
from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import Qt
queue = Queue()
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
layout = QVBoxLayout()
label = QLabel("Change modes")
btn1 = QPushButton("MODE 1")
btn2 = QPushButton("MODE 2")
layout.addWidget(label)
layout.addWidget(btn1)
layout.addWidget(btn2)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
btn1.clicked.connect(self.mode1)
btn2.clicked.connect(self.mode2)
self.show()
def mode1(self):
queue.put("mode1")
def mode2(self):
queue.put("mode2")
if __name__ == '__main__':
app = QApplication()
window = MainWindow()
app.exec()
mode = "none"
while True:
_mode = queue.get()
if mode != _mode:
mode = _mode;
print(f"mode: {mode}")
# do stuff here
the only way that the while loop executes is when i close the window.
Traditional Python multiprocessing/multithreading libraries such as multiprocessing
and threading
do not work well with Qt-like (PyQt
and PySide
) graphical programs. Fortunately, among other solutions, PySide
provides the QThread
interface, allowing multithreading in PySide
graphical interfaces. It can be applied to your program as follows:
import threading
from queue import Queue
from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import Qt, QThread
queue = Queue()
class Worker(QThread):
def __init__(self):
super(Worker, self).__init__()
def run(self):
mode = "none"
while True:
_mode = queue.get()
if mode != _mode:
mode = _mode;
print(f"mode: {mode}")
# do stuff here
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
layout = QVBoxLayout()
label = QLabel("Change modes")
btn1 = QPushButton("MODE 1")
btn2 = QPushButton("MODE 2")
layout.addWidget(label)
layout.addWidget(btn1)
layout.addWidget(btn2)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
btn1.clicked.connect(self.mode1)
btn2.clicked.connect(self.mode2)
self.show()
self.worker = Worker() # Create a Worker instance
self.worker.start() # Start the Worker instance (which calls the run function of the Worker instance)
def mode1(self):
queue.put("mode1")
def mode2(self):
queue.put("mode2")
def closeEvent(self, event):
self.worker.terminate() # When the window closes, stop the thread
if __name__ == '__main__':
app = QApplication()
window = MainWindow()
app.exec()
Please note the changed import statement of PySide6.QtCore
(to import QThread
), the addition of the self.worker
variable in the __init__
function of the MainWindow
class (to actually start the thread), as well as the addition of a closeEvent
function in the MainWindow
class (to terminate the thread when the window closes).