How to call keyPressEvent in PyQt5 by returnPressed?
-
Hi,
I'm currently using PyQt5, and I need to detect when return is pressed inside it.
I currently have this code:self.intextbox.returnPressed.connect(self.keyPressEvent)
and my event function:
def keyPressEvent(self, e): if e.key() == 16777220: #16777220 seems to be enter self.appendtotextbox()
however it throws the exception:
<class 'TypeError'> keyPressEvent() missing 1 required positional argument: 'e' None TypeError: keyPressEvent() missing 1 required positional argument: 'e'
How would I be able to achieve it? (intextbox is a QLineEdit)
-
Resolving the problem:
First I am going to do more than just answer this question I am going to try and also explain how one goes about perhaps solving this issue by oneself -- self sufficiency is a very important element for any programmer and should always be your first line of action
So first I did a Google search on "pyqt5 keyPressEvent" I found numerous examples on how this is done.
This particular example which was actually PyQt4 ( http://python.6.x6.nabble.com/Keypressevent-td1792690.html ) does cover the basic elements and has a semi-working program to help one understand the keypress-event (granted it has to be tweaked to be made pyqt5 python 3.7 compliant -- fix the print( ) function calls, remove in-code references to QtCore and QtGui as well as add a reference to QtWidgets). So here is a pyqt5 working version of that example:
import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class MainGui(object): def setupUi(self, MainWindow): MainWindow.resize(218, 379) self.centralwidget = QWidget(MainWindow) self.layout = QVBoxLayout(self.centralwidget) self.p_text = QPlainTextEdit(self.centralwidget) self.layout.addWidget(self.p_text) MainWindow.setCentralWidget(self.centralwidget) self.p_text.keyPressEvent = self.keyPressEvent def keyPressEvent(self, e): print("event", e) if e.key() == Qt.Key_Return : print(' return') elif e.key() == Qt.Key_Enter : print(' enter') if __name__ == "__main__": app = QApplication(sys.argv) MainWindow = QMainWindow() ui = MainGui() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
So as you can see to grab the KeyPress Event we have to have a handle to the object (self.p_text) and we have to set that objects keyPressEvent to your local function (self.p_text.keyPressEvent = self.keyPressEvent) with (self.keyPressEvent) being our local function. Now while this works its not very pretty code-wise nor very simple and my motto is always K.I.S.S. (Keep It Simple but Smart) and I stress the Simple part because making it unnecessarily more complex, while it might need more intelligence to do, is technically not all that Smart since it is not easily understood a few months down the road even by the original coder.
Also keep in mind that this intercepts the normal keypress event (aka it overrides the function) and as such destroys the normal functionality of that event handler which would mean we would then need to also recode all of its functionality. So to fix this I did a quick Google search of "pyqt5 keyPressEvent pass through" and found this: ( https://stackoverflow.com/questions/27475940/pyqt-connect-to-keypressevent ) and this explains how to catch the event and then pass it on so that it is handled properly. So with that determined let us take the above code and make it a bit more pythonic and not destroy the basic functionality.
# Try not to include more than what you actually need from sys import exit as sysExit from PyQt5.QtCore import Qt #from PyQt5.QtGui import from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget from PyQt5.QtWidgets import QPlainTextEdit, QHBoxLayout class CenterObject(QPlainTextEdit): # This of course handles our core object from which we want # to capture the keypress event and thus gives that handle # that we need in a much cleaner manner def __init__(self): QPlainTextEdit.__init__(self) # since this Class is our handle we can simply override # its keyPressEvent directly def keyPressEvent(self, keyEvent): # This passes the Event along its merry way to be handled as it normally would be # Note this could be done first or last or in the middle just as long as its done # The where it is handled part is greatly dependent upon what you are planning to # do. Still it is an event so the sooner the better -- also you can change what is # being passed on as well and if so this would naturally come after you have made # whatever changes you want to make -- you could (conditionally) block this event # from completing by simply not passing it on super(CenterObject, self).keyPressEvent(keyEvent) print("Event :", keyEvent) if keyEvent.key() == Qt.Key_Return : print('*** Return pressed') elif keyEvent.key() == Qt.Key_Enter : print('*** Enter pressed') class CenterPane(QWidget): # While this class does not currently contain much what it does # contain is essential and it allows for expansion later on -- # for example what if instead of a single textbox one wants a # tree and a list view that would be handled here def __init__(self): QWidget.__init__(self) objCntrPane = CenterObject() hbox = QHBoxLayout(self) hbox.addWidget(objCntrPane) class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) winLeft = 100 winTop = 100 winWidth = 400 winHeight = 300 self.setWindowTitle('Main Window') self.setGeometry(winLeft, winTop, winWidth, winHeight) self.setCentralWidget(CenterPane()) # This routine needs to be made as simple as possible if __name__ == "__main__": # Note: Do not use "sys.argv" unless you actually plan to handle command # line directives as it is more secure as well as much simpler app = QApplication([]) GUI = MainWindow() GUI.show() sysExit(app.exec_())
So there you have it -- not only how to properly handle the keyPressEvent but also the how to find an answer on your own. Oh by the way thank you for this question as I had not actually known how to do this myself until I looked into answering this question but it is something I was going to need to know myself.
-
Your welcome -- and I understand I think my 2 searches required me to look at a few websites before finding something useful -- so all I can say is never get discouraged, never give up -- basically I can often find something faster than I can get a response to a posted question so I always do that first -- and frankly sometimes its the search criterion one uses that helps find that needle in the mountain of hay that is the internet which is why I posted what I searched for -- the Truth is out there :) you just got to find the correct light switch in order to see it