Search code examples
pythonpython-3.xpyqtpyqt5qkeyevent

how to detect a key release in pyqt


I want to create a PyQt5 window (Windows OS) which recognizes a button click with holding CTRL button. I successfully created a handler which recognizes CTRL key press but it couldn't find the pressing and releasing of a button which i need to call and dismiss button click event. I did a lot of search but the resources for PyQt5 seems pretty low. Any help is appreciated :)

import time
from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.setupUi(self)
        self.show()
        self.signals()
        self.bleahOK=True

    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(392, 255)
        self.unlockButton = QtWidgets.QPushButton(Dialog)
        self.unlockButton.setGeometry(QtCore.QRect(10, 180, 171, 51))
        self.unlockButton.setObjectName("unlockButton")
        self.lockButton = QtWidgets.QPushButton(Dialog)
        self.lockButton.setGeometry(QtCore.QRect(220, 180, 151, 51))
        self.lockButton.setObjectName("lockButton")
        self.label = QtWidgets.QLabel(Dialog)
        self.label.setGeometry(QtCore.QRect(30, 30, 331, 71))
        font = QtGui.QFont()
        font.setPointSize(12)
        self.label.setFont(font)
        self.label.setObjectName("label")
        self.lineEdit = QtWidgets.QLineEdit(Dialog)
        self.lineEdit.setGeometry(QtCore.QRect(30, 120, 261, 31))
        font = QtGui.QFont()
        font.setPointSize(18)
        self.lineEdit.setFont(font)
        self.lineEdit.setObjectName("lineEdit")

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.unlockButton.setText(_translate("Dialog", "OK"))
        self.lockButton.setText(_translate("Dialog", "Lock"))
        self.label.setText(_translate("Dialog", ""))
        self.lineEdit.setText(_translate("Dialog", ""))

    def signals(self):
        self.unlockButton.clicked.connect(self.unlock)

    def unlock(self):
        if 1: print('ff')            

    def keyPressEvent(self, event):
         if type(event) == QtGui.QKeyEvent: #Unable to find when the key was released
            print (event.key())          
            event.accept()
         else:
             event.ignore()     

    def lock(self):
        print("Test")

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    # ui.signals()
    # Dialog.show()
    sys.exit(app.exec_())

Solution

  • I recommend you not to modify the code generated by Qt Designer, instead create a class that inherits the appropriate widget and use that class as an interface as I recommend PyQt. Going to the problem, you have to use the keyReleaseEvent method to listen when a key is released:

    import time
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class Ui_Dialog(object):
        def setupUi(self, Dialog):
            Dialog.setObjectName("Dialog")
            Dialog.resize(392, 255)
            self.unlockButton = QtWidgets.QPushButton(Dialog)
            self.unlockButton.setGeometry(QtCore.QRect(10, 180, 171, 51))
            self.unlockButton.setObjectName("unlockButton")
            self.lockButton = QtWidgets.QPushButton(Dialog)
            self.lockButton.setGeometry(QtCore.QRect(220, 180, 151, 51))
            self.lockButton.setObjectName("lockButton")
            self.label = QtWidgets.QLabel(Dialog)
            self.label.setGeometry(QtCore.QRect(30, 30, 331, 71))
            font = QtGui.QFont()
            font.setPointSize(12)
            self.label.setFont(font)
            self.label.setObjectName("label")
            self.lineEdit = QtWidgets.QLineEdit(Dialog)
            self.lineEdit.setGeometry(QtCore.QRect(30, 120, 261, 31))
            font = QtGui.QFont()
            font.setPointSize(18)
            self.lineEdit.setFont(font)
            self.lineEdit.setObjectName("lineEdit")
    
            self.retranslateUi(Dialog)
            QtCore.QMetaObject.connectSlotsByName(Dialog)
    
        def retranslateUi(self, Dialog):
            _translate = QtCore.QCoreApplication.translate
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
            self.unlockButton.setText(_translate("Dialog", "OK"))
            self.lockButton.setText(_translate("Dialog", "Lock"))
            self.label.setText(_translate("Dialog", ""))
            self.lineEdit.setText(_translate("Dialog", ""))
    
    class Dialog(QtWidgets.QDialog, Ui_Dialog):
        def __init__(self, parent=None):
            super(Dialog, self).__init__(parent)
            self.setupUi(self)
            self.is_key_ctrl_pressed = False
            self.unlockButton.clicked.connect(self.unlock)
    
        @QtCore.pyqtSlot()
        def unlock(self):
            if self.is_key_ctrl_pressed:
                print("unlock")
    
        def keyPressEvent(self, event):
            if event.key() == QtCore.Qt.Key_Control:
                self.is_key_ctrl_pressed = True
            super(Dialog, self).keyPressEvent(event)
    
        def keyReleaseEvent(self, event):
            if event.key() == QtCore.Qt.Key_Control:
                self.is_key_ctrl_pressed = False
            super(Dialog, self).keyReleaseEvent(event)
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        w = Dialog()
        w.show()
        sys.exit(app.exec_())