简体   繁体   English

如何正确编写PyQT5事件函数

[英]How to write correctly PyQT5 event function

How can I correctly write the event function to pass from one QLineEdit to another one by pressing the enter key?如何正确编写事件函数以通过按 Enter 键从一个 QLineEdit 传递到另一个 QLineEdit?

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).现在我想了解如何用这段代码做同样的事情(我认为问题出在 super() 和init 上,但我不知道为什么)。

UNWorking Basic Example UNWorking 基本示例

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_())

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.第二个示例不起作用,因为您试图覆盖event方法,该方法仅适用于 QWidget 子类,而您的Ui_MainWindow是一个简单的 python object子类,因此永远不会被调用。

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. Qt 在任何 QWidget 上调用event()方法,并且由于您在第一个示例中覆盖了它,因此实际上调用了您的方法。 In the second example you're not overriding the QWidget event , but you're just creating a function that is never called by anything.在第二个示例中,您没有覆盖 QWidget event ,而只是创建了一个永远不会被任何东西调用的函数。

Theoretically you could overwrite the event method of the MainWindow object in setupUi (that's what's called "monkey patching"):理论上你可以覆盖setupUi MainWindow对象的event方法(这就是所谓的“猴子补丁”):

    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.但这不起作用,因为您在该函数中所指的self实际上是Ui_MainWindow实例,而不是实际的 QMainWindow 实例。 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.虽然您可以使用 lambda,并在 MainWindow 实例中添加参数,但我强烈建议您不要这样做,以下解释将阐明您不应该这样做的原因。


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. 做你想做的事情没有意义,原因很简单:修改或尝试模仿`pyuic`生成文件的行为是**永远**不应该做的事情。

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.不鼓励编辑主要是因为每当您需要从 Designer 更改 UI 中的某些内容时,您最终都会尝试将新生成的代码(希望您同时没有覆盖文件)与现有代码集成,这将通常会导致大量错误、问题、崩溃和头痛。

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.此外,虽然我可以理解您有兴趣研究它的工作原理,但除了阅读如何在setupUi创建界面setupUi ,没有什么可学习的了。 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 . pyuic 文件仅用作简化 PyQt 编程的“实用程序层”,它们应始终仅按照有关使用 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 ;注意:我假设您已经使用pyuic再次生成了该文件该文件名为ui_mainwindow.py also, note that if you're using a QMainWindow in designer, you must subclass from the same class (QMainWindow, not QWidget);另外,请注意,如果您在设计器中使用 QMainWindow,则必须从同一类(QMainWindow,而不是 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.最后,由于您已经是 QMainWindowUi_MainWindow 的子类,您必须创建一个Working实例,而不是 QMainWindow 之一,也不是 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.另一种可能性是使用uic模块,它允许直接导入.ui文件,而无需每次都重新.ui整个界面。

 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) # ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM