Search code examples
python-3.xevent-handlingpyqt5qdial

How to increase the PyQt5 app.processEvents() queue depth?


I used PyQt5 to create a simple GUI, which - among other things - contain QDial widgets. I want to change the colour of a particular QDial, and the colour of a corresponding QLineEdit that displays the relevant value on QDial rotation.

I designed the complete QWidget using QDesigner, then converted the .ui file to a .py file, and then wrote a new python file with the 'logic' class inheriting from the original ui/py/Designer output.

The relevant code is as follows:

 class Logic(QtWidgets.QMainWindow, Ui_From_Designer):
    def __init__(self, *args, **kwargs):
        QtWidgets.QMainWindow.__init__(self, *args, **kwargs)      
        self.setupUi(self)
        (...)
        self.dial_TL.valueChanged.connect(self.OnChange_Dial_TL)
        (...)

    def OnChange_Dial_TL(self):
        self.lineEdit_TL.setStyleSheet("background-color: rgb(160, 40, 40);")
        self.dial_TL.setStyleSheet("background-color: rgb(160, 40, 40);")
        self.lineEdit_TL.setText(hex(self.dial_TL.value())[2:].upper())
        app.processEvents()
        time.sleep(0.01)
        self.lineEdit_TL.setStyleSheet("")
        self.dial_TL.setStyleSheet("") 
        app.processEvents()
        time.sleep(0.01)

Now, the GUI works fine and does the job, however, when the QDial is rotated (mouse wheel) for too long, the interpreter eventually crashes. There are no typical traceback errors - the only symptom is that Windows freezes the GUI, and three seconds later the window is destroyed.

This behaviour does not occur when I remove the app.processEvents() lines from the above code - hence I suspect that the input from the mouse wheel while rotating QDials is too fast / it's too much to handle. But then without app.processEvents() the colour does not change on QDial.changeValue.

Is there any way to optimise the code above to handle more input, or to increase the depth of app.processEvents queue, so it does not crash?


Solution

  • If you want to do a task after a while (like removing the background color) then you shouldn't use time.sleep() + QApplication::processEvents(), instead you should use a QTimer:

    def OnChange_Dial_TL(self, value):
        self.lineEdit_TL.setStyleSheet("background-color: rgb(160, 40, 40);")
        self.dial_TL.setStyleSheet("background-color: rgb(160, 40, 40);")
        self.lineEdit_TL.setText(hex(value)[2:].upper())
        QtCore.QTimer.singleShot(10, self.OnTimeout)
    
    
    def OnTimeout(self):
        self.lineEdit_TL.setStyleSheet("")
        self.dial_TL.setStyleSheet("")