How can I correctly write the event function to pass from one QLineEdit to another one by pressing the enter key?
I know how to do that in this way:
Working Example
import sys from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QFormLayout from PyQt5.QtCore import Qt, QEvent class working(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.show() self.x = QLineEdit(self) self.x1 = QLineEdit(self) layout = QFormLayout(self) layout.addRow("x:", self.x) layout.addRow("x1:", self.x1) def event(self, event): if event.type() == QEvent.KeyPress: if event.key() in (Qt.Key_Return, Qt.Key_Enter): self.focusNextPrevChild(True) return super().event(event) def main(): app = QApplication(sys.argv) ex = working() sys.exit(app.exec_()) if __name__ == '__main__': main()
Now i want to understand how to do the same with this code (i think that the problem is with super() and init but i don’t know why).
UNWorking Basic Example
from PyQt5 import QtCore, QtWidgets, QtGui class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(193, 119) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout_2.setObjectName("verticalLayout_2") self.x = QtWidgets.QLineEdit() self.verticalLayout_2.addWidget(self.x) self.x1 = QtWidgets.QLineEdit() self.verticalLayout_2.addWidget(self.x1) MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "0")) def event(self, event): if event.type() == QEvent.KeyPress: if event.key() in (Qt.Key_Return, Qt.Key_Enter): self.focusNextPrevChild(True) return super().event(event) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
Advertisement
Answer
The second example does not work because you’re trying to override the event
method, which is a method available only for QWidget subclasses, while your Ui_MainWindow
is a simple python object
subclass, so it will never be called.
The event()
method is called by Qt on any QWidget, and since you are overriding it in the first example, your method is actually called. In the second example you’re not overriding the QWidget event
, but you’re just creating a function that is never called by anything.
Theoretically you could overwrite the event
method of the MainWindow
object in setupUi
(that’s what’s called “monkey patching”):
def setupUi(self, MainWindow): # ... MainWindow.event = self.event
But that won’t work as the self
you’re referring to in that function is actually the Ui_MainWindow
instance, not the actual QMainWindow instance. While you could use a lambda, and add the argument with the MainWindow instance, I’d strongly advise against that, and the following explanation will clarify why you shouldn’t do it.
There’s no point in doing what you’re trying to achieve, for a simple reason: modifying or trying to mimic the behavior of `pyuic` generated files is something that should **NEVER** be done.
Editing is discouraged mostly because whenever you need to change something in the UI from Designer, you’ll end up trying to integrate the new generated code (hoping that you’ve not overwritten the file in the meantime) with the existing one, which will normally result in tons of errors, issues, crashes and headaches.
Editing or mimicking is discouraged as it makes very hard to implement simple class operations or override existing methods. Also, while I can understand you’re interest in studying how it works, except for reading how the interface is created within the setupUi
, there’s nothing more to learn there. The pyuic files are intended only as an “utility layer” to ease up programming in PyQt, they should always only be imported and used as suggested in the official guidelines about using Designer.
If you want to implement the event of the first example, you’ll need to use your own subclass and use one of the approaches suggested in the link above. The most common and easy to use is the multiple inheritance approach:
import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QLineEdit, QFormLayout from PyQt5.QtCore import Qt, QEvent from ui_mainwindow import Ui_MainWindow class Working(QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) def event(self, event): if event.type() == QEvent.KeyPress: if event.key() in (Qt.Key_Return, Qt.Key_Enter): self.focusNextPrevChild(True) return super().event(event) if __name__ == "__main__": import sys app = QApplication(sys.argv) mainWindow = Working() mainWindow.show() sys.exit(app.exec_())
Note: I’m assuming that you’ve generated the file again with pyuic
and that is named ui_mainwindow.py
; also, note that if you’re using a QMainWindow in designer, you must subclass from the same class (QMainWindow, not QWidget); finally, since you’re already subclassing from QMainWindow and Ui_MainWindow, you have to create an instance of Working
, not one of QMainWindow, nor one of Ui_MainWindow.
Another possibility is to use the uic
module, which allows to import the .ui
file directly without the need to rebuild the whole interface everytime.
import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QLineEdit, QFormLayout from PyQt5.QtCore import Qt, QEvent from PyQt5.uic import loadUi class Working(QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() loadUi('mainWindow.ui', self) # ...