Search code examples
pyqt5qwidgetqinputdialog

How to close a QInputDialog with after a defined amount of time


I'm currently working on an application that run in the background and sometime create an input dialog for the user to answer. If the user doesn't interact, I'd like to close the dialog after 30 seconds. I made a QThread that act like a timer and the "finished" signal should close the dialog. I unfortunately cannot find a way to close it.

At this point I'm pretty much lost. I completely new to QThread and a beginner in PyQt5

Here is a simplified version of the code (we are inside a class running a UI):

    def Myfunction(self,q):
        # q : [q1,q2,q3]
        self.popup = counter_thread()
        self.popup.start()        

        self.dial = QInputDialog

        self.popup.finished.connect(self.dial.close)

        text, ok = self.dial.getText(self, 'Time to compute !', '%s %s %s = ?'%(q[0], q[2], q[1]))
        #[...]

I tried ".close()" and others but i got this error message:

TypeError: close(self): first argument of unbound method must have type 'QWidget'

I did it in a separated function but got the same problem...


Solution

  • You cannot close it because the self.dial you created is just an alias (another reference) to a class, not an instance.

    Also, getText() is a static function that internally creates the dialog instance, and you have no access to it.

    While it is possible to get that dialog through some tricks (installing an event filter on the QApplication), there's no point in complicating things: instead of using the static function, create a full instance of QInputDialog.

        def Myfunction(self,q):
            # q : [q1,q2,q3]
            self.popup = counter_thread()
    
            self.dial = QInputDialog(self) # <- this is an instance!
            self.dial.setInputMode(QInputDialog.TextInput)
            self.dial.setWindowTitle('Time to compute !')
            self.dial.setLabelText('%s %s %s = ?'%(q[0], q[2], q[1]))
    
            self.popup.finished.connect(self.dial.reject)
            self.popup.start()
    
            if self.dial.exec():
                text = self.dial.textValue()
    

    Note that I started the thread just before showing the dialog, in the rare case it may return immediately, and also because, for the same reason, the signal should be connected before starting it.