I've written a simple window with a start button that starts a Qthread. After a few instructions in the thread, I would like to display a SubWindow using Signal. Unfortunately, Qthread does not stop after displaying subWindow.
I'm looking for a solution like while Qthread is running: stop the Qthread, display a SubWindow, input the data, and send it directly to the Qthread, then start the thread.
One way I can think of is to open a window directly from the thread, but I don't think that's necessarily a good practice because I need to create a new instance of the app. In addition, there is still the problem of sending data from SubWindow to the thread
Problems:
- how to stop Qthread while displaying sub window
- how to pass data from sub window to Qthread
Code:
from PySide2 import QtWidgets
from PySide2 import QtCore
import sys, time
class InsertWindow(QtWidgets.QDialog):
signal_return_data = QtCore.Signal(str)
def __init__(self):
super().__init__()
self.layout = QtWidgets.QVBoxLayout()
self.line = QtWidgets.QLineEdit("")
self.push = QtWidgets.QPushButton("Send")
self.push.clicked.connect(self.send_it)
self.layout.addWidget(self.line)
self.layout.addWidget(self.push)
self.setLayout(self.layout)
def send_it(self):
if self.line.text() == '':
msg = QtWidgets.QMessageBox()
msg.setText("Not Empty")
msg.show
else:
self.signal_return_data.emit(self.line.text())
self.close()
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QVBoxLayout()
self.txt = QtWidgets.QLabel("Welcome!")
self.push = QtWidgets.QPushButton("Start")
self.progres = QtWidgets.QProgressBar()
self.layout.addWidget(self.txt)
self.layout.addWidget(self.push)
self.layout.addWidget(self.progres)
self.setLayout(self.layout)
self.push.clicked.connect(self.p_start)
def show_insert_popup(self):
self.insert_win = InsertWindow()
self.insert_win.signal_return_data.connect(self.send_to_thread)
self.insert_win.exec_()
def p_start(self):
self.progres.setMinimum(0)
self.progres.setMaximum(0)
self.worker = Worker()
self.worker.signal_open_insert.connect(self.show_insert_popup)
self.worker.finished.connect(self.stop_)
self.worker.start()
def stop_(self):
self.progres.setMinimum(0)
self.progres.setMaximum(100)
@QtCore.Slot(str)
def send_to_thread(self, txt):
self.txt.setText(f"{txt} Get It here, but need it in thread")
class Worker(QtCore.QThread):
signal_open_insert = QtCore.Signal()
def run(self):
for x in range(2):
print("I working in thread")
time.sleep(2)
# here I need stop thread (until the data will entered ), open subwindow, and get entered data to display
self.signal_open_insert.emit()
for x in range(2):
print("Here i would like display dafa from insert window")
time.sleep(1)
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
app.exec_()
CodePudding user response:
probably just send it over a queue, queue.get()
is a blocking function so it will pause the thread execution until someone puts something in the queue.
just create a queue in the caller, let's call it result_queue
, the child will call result_queue.get()
on it to sleep and wait for an item to be put in it and the main thread will put
the txt in it using self.result_queue.put(txt)
.
just make sure you always put
something in it even if an exception happens or the user cancels the operation otherwise the thread will hang forever, as i did by overriding the reject
method of the dialog box.
from PySide2 import QtWidgets
from PySide2 import QtCore
import sys, time
import queue
from typing import Optional
class InsertWindow(QtWidgets.QDialog):
signal_return_data = QtCore.Signal(str)
def __init__(self):
super().__init__()
self.layout = QtWidgets.QVBoxLayout()
self.line = QtWidgets.QLineEdit("")
self.push = QtWidgets.QPushButton("Send")
self.push.clicked.connect(self.send_it)
self.layout.addWidget(self.line)
self.layout.addWidget(self.push)
self.setLayout(self.layout)
def reject(self) -> None:
self.signal_return_data.emit('')
super().reject()
def send_it(self):
if self.line.text() == '':
msg = QtWidgets.QMessageBox()
msg.setText("Not Empty")
msg.show
else:
self.signal_return_data.emit(self.line.text())
self.close()
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QVBoxLayout()
self.txt = QtWidgets.QLabel("Welcome!")
self.push = QtWidgets.QPushButton("Start")
self.progres = QtWidgets.QProgressBar()
self.layout.addWidget(self.txt)
self.layout.addWidget(self.push)
self.layout.addWidget(self.progres)
self.setLayout(self.layout)
self.push.clicked.connect(self.p_start)
self.result_queue: Optional[queue.Queue] = None
def show_insert_popup(self):
self.insert_win = InsertWindow()
self.insert_win.signal_return_data.connect(self.send_to_thread)
self.insert_win.exec_()
def p_start(self):
self.progres.setMinimum(0)
self.progres.setMaximum(0)
self.result_queue = queue.Queue()
self.worker = Worker(self.result_queue)
self.worker.signal_open_insert.connect(self.show_insert_popup)
self.worker.finished.connect(self.stop_)
self.worker.start()
def stop_(self):
self.progres.setMinimum(0)
self.progres.setMaximum(100)
@QtCore.Slot(str)
def send_to_thread(self, txt):
self.result_queue.put(txt)
self.txt.setText(f"{txt} Get It here, but need it in thread")
class Worker(QtCore.QThread):
signal_open_insert = QtCore.Signal()
def __init__(self, results_queue: queue.Queue):
self.results_queue = results_queue
super().__init__()
def run(self):
for x in range(2):
print("I working in thread")
time.sleep(2)
# here I need stop thread (until the data will entered ), open subwindow, and get entered data to display
self.signal_open_insert.emit()
result = self.results_queue.get()
for x in range(2):
print("Here i would like display dafa from insert window")
print(result)
time.sleep(1)
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
app.exec_()