thread communication, stop the work of a thread until data is entered PySide

Question:

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_()
Asked By: AnnAc0nda

||

Answers:

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_()
Answered By: Ahmed AEK
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.