1

I have a scenario where I am outsourcing my execution part to QThread and during execution i have a need to launch QDialog to take some user inputs within QThread.

For scenario where QDialog calls are not in picture is working fine but for snippet where QDialog code runs, i get

QPixmap: It is not safe to use pixmaps outside the GUI thread
QObject::startTimer: timers cannot be started from another thread
QApplication: Object event filter cannot be in a different thread.

and execution stops abruptly.

My QDialog code :

class ResultDialog(QDialog):
    def __init__(self, parent = None):
        super(ResultDialog, self).__init__(parent)

        self.resultIndex = -1
        grid_layout = QGridLayout(self)

        failreplace_layout = QHBoxLayout(self)
        faildontreplace_layout = QHBoxLayout(self)

        self.info_lbl = QLabel(self)
        self.info_lbl.setText("Image comparision failed for screen resolution")

        self.failreplace_radio = QRadioButton(self)
        self.failreplace_radio.setText("Fail and Replace Reference Image")
        self.faildontreplace_radio = QRadioButton(self)
        self.faildontreplace_radio.setText("Fail and Do not replace Reference Image")

        self.tester_comment = QPlainTextEdit(self)
        self.tester_comment.clear()
        self.tester_comment.setPlainText('Tester comment is desired')
        self.tester_comment.setDisabled(True)

        self.buttonsend = QPushButton(self)
        self.buttonsend.setText("Ok")
        self.buttonsend.setCheckable(True)

        grid_layout.addWidget(self.info_lbl,0,0)
        grid_layout.addWidget(self.failreplace_radio,1,0)
        grid_layout.addWidget(self.faildontreplace_radio,2,0)
        grid_layout.addWidget(self.tester_comment,3,0)

        self.loop = QtCore.QEventLoop()

        # OK and Cancel buttons
        grid_layout.addWidget(self.buttonsend, 4,0)

        self.buttonsend.clicked.connect(self.submitclose)
        self.failreplace_radio.clicked.connect(self.onfailreplace_radio)
        self.faildontreplace_radio.clicked.connect(self.onfaildontreplace_radio)

    def submitclose(self):
        self.loop.quit()
        self.accept()

    def onfailreplace_radio(self):
        print "onfailreplace_radio "
        self.tester_comment.setDisabled(False)
        self.buttonsend.setDisabled(False)
        self.tester_comment.clear()
        self.resultIndex = 0

    def onfaildontreplace_radio(self):
        print "onfaildontreplace_radio "
        self.tester_comment.setDisabled(False)
        self.buttonsend.setDisabled(False)
        self.tester_comment.clear()
        self.resultIndex = 1

    # static method to create the dialog and return
    @staticmethod      
    def returnSelection(parent):
        dialog = ResultDialog(parent)
        result = dialog.show()
        dialog.loop.exec_();

        print "dialog.buttonsend.isChecked() ", dialog.buttonsend.isChecked()
        if dialog.buttonsend.isChecked() == True:
            if not str(dialog.tester_comment.toPlainText()):
                QMessageBox.critical(dialog, 'Tester Comment', 'Tester comment is desired')
                return (dialog.resultIndex, 'NA')
            else:
                return (dialog.resultIndex, str(dialog.tester_comment.toPlainText()))

if __name__ == "__main__":
    app = QApplication([])
    ok = ResultDialog.returnSelection()
    print("{}".format(ok))
    app.exec_()

And i am calling it from Qthread.run() like :

index, testercomment = ResultDialog.returnSelection(None)
    if index == 0 or index == 1:
        self.resumeExec()                                            
    else:
        self.sync.lock();    
        self.pauseCond.wait(self.sync)
        self.sync.unlock();    
Pawankumar Dubey
  • 387
  • 1
  • 6
  • 21
  • `QPixmap` is bound to the mainthread (GUIthread), see if you could use `QImage`. For the timer, first move your object to its new thread or create the object in the new thread and initialize and start the timer there. Timers always run in the thread they get created in. Same is for the event filter. Every thread has its own event queue. If one creates a filter on thread A it will use the event queue of this given thread. Create the filter directly on the foreign thread. Create and work with UI always on the main thread. If you need long execution on another thread, communicate using signals. – Sebastian Lange Feb 07 '17 at 12:29
  • 2
    You can't use Qt GUI components in any thread *other* than that on which you initialized Qt -- generally the thread on which the `QApplication` was instantiated. – G.M. Feb 07 '17 at 12:41
  • Exactly, now i am calling QDialog from my MainWindow itself but condition on which QDialog will be called is decided by signal which Thread will send to Mainwindow – Pawankumar Dubey Feb 08 '17 at 16:16

0 Answers0