简体   繁体   English

为什么我的 keyPressEvent 没有注册或工作 PyQt5?

[英]Why does my keyPressEvent not register or work PyQt5?

This program is for a school project.该计划是针对学校项目的。 I am adding a simple keyPressEvent to my PyQt5 application to close the program.我正在向我的 PyQt5 应用程序添加一个简单的 keyPressEvent 以关闭程序。 I believe I have added the right code, yet the keyPressEvent will not even register a key click.我相信我已经添加了正确的代码,但 keyPressEvent 甚至不会注册按键点击。 I have tried setting the focus using self.setFocusPolicy(Qt.StrongFocus) but it did not work.我曾尝试使用self.setFocusPolicy(Qt.StrongFocus)设置焦点,但没有奏效。 I have omitted the irrelevant widgets to the code我在代码中省略了不相关的小部件

import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, 
                                QLabel, QPushButton, QWidget, 
                                QStackedLayout, QVBoxLayout, 
                                QStackedWidget, QLineEdit,
                                QCheckBox, QMessageBox,
                                QGridLayout)
from PyQt5.QtCore import Qt

class UI(QWidget):

    def setupUI(self, Main):

        self.width = 900
        self.height = 500

        self.pages = QStackedLayout()

        self.login = QWidget()
        self.register = QWidget()
        self.home = QWidget()

        self.loginUI()
        self.homeUI()

        self.pages.addWidget(self.login)
        self.pages.addWidget(self.home)

    def loginUI(self):

        self.login_Layout = QGridLayout(self.login)

        self.login.setFixedSize(300, 200)

        self.loginButton = QPushButton("Log In")
        self.login_Layout.addWidget(self.loginButton, 0, 0)

    def homeUI(self):

        self.home_Layout = QGridLayout(self.home)

        self.home.setFixedSize(self.width, self.height)
        self.Button1 = QPushButton("Log Out")

        self.Button2 = QPushButton("HELLO")

        self.home_Layout.addWidget(self.Button1, 0, 0, 1, 1)
        self.home_Layout.addWidget(self.Button2, 0, 1)

class Main(QMainWindow, UI):

    def __init__(self):
        super(Main, self).__init__()

        self.setupUI(self)

        self.loginButton.clicked.connect(self.GoTohomePage)
        self.Button1.clicked.connect(self.GoTologinPage)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            print("closed")

    def GoTohomePage(self):
        self.pages.setCurrentIndex(1)
    def GoTologinPage(self):
        self.pages.setCurrentIndex(0)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    M = Main()
    sys.exit(app.exec())

There is a big conceptual problem in your code, and it's just due to a subtle "non-bug" in Qt that your program "seems" to work (as in "it works = it shows").您的代码中有一个很大的概念问题,这只是由于 Qt 中的一个微妙的“非错误”,您的程序“似乎”可以工作(如“它有效 = 它显示”)。

The main issue is that you're trying to inherit from both QMainWindow _ and _ QWidget, which doesn't make much sense, since QMainWindow already inherits QWidget.主要问题是您试图从 QMainWindow __ QWidget 继承,这没有多大意义,因为 QMainWindow 已经继承了 QWidget。

What you're actually seeing is not your main window (the instance of Main ), but all the individual QWidgets you created ( self.login , etc.).您实际看到的不是您的主窗口( Main的实例),而是您创建的所有单个QWidgets ( self.login等)。

This is a "non-bug" (probably related to this report ): when a new widget is added to a QStackedLayout, it tries to show it.这是一个“非错误”(可能与此报告有关):当新的小部件添加到 QStackedLayout 时,它会尝试显示它。 If the stacked layout does not have a widget in its constructor and is not set to any widget, for some reason Qt shows that widget as soon as the application is exec 'd.如果堆叠布局的构造函数中没有小部件并且未设置为任何小部件,则出于某种原因,Qt 会在应用程序exec立即显示该小部件。

It shouldn't do that, yes, but you also shouldn't create a layout without setting it to a widget (as you shouldn't normally create a class with multiple inheritance sharing the same direct ancestor, QWidget in this case).它不应该这样做,是的,但是您也不应该在不将其设置为小部件的情况下创建布局(因为您通常不应该创建一个具有多个继承的类,该类共享同一个直接祖先,在这种情况下为 QWidget)。 What's also happening is that, whenever you call self.pages.setCurrentIndex , the stacked layout tries to show the new widget and hide the previous.还会发生的情况是,每当您调用self.pages.setCurrentIndex ,堆叠布局都会尝试显示新小部件并隐藏前一个小部件。 This is ok for normal situations (most commonly, when using QStackedWidget, but it has an unexpected result in yours: since no widget is set for the stacked layout, its widget shouldn't be shown at all (actually, its behavior is not technically wrong, but that's not the issue here).这对于正常情况是可以的(最常见的是,当使用 QStackedWidget 时,但它在您的情况下会产生意想不到的结果:由于没有为堆叠布局设置小部件,它的小部件根本不应该显示(实际上,它的行为在技术上不是错了,但这不是这里的问题)。

The solution is to implement everything in the Main class, create a central widget and set the stacked layout for that widget.解决方案是在Main类中实现所有内容,创建一个中央小部件并为该小部件设置堆叠布局。

class Main(QMainWindow, UI):

    def __init__(self):
        super(Main, self).__init__()

        self.setupUI(self)

        self.loginButton.clicked.connect(self.GoTohomePage)
        self.Button1.clicked.connect(self.GoTologinPage)

    def setupUI(self, Main):

        self.width = 900
        self.height = 500

        centralWidget = QWidget() self.setCentralWidget(centralWidget) self.pages = QStackedLayout() centralWidget.setLayout(self.pages)
        # the two lines above are the same as the following:
        # self.pages = QStackedLayout(centralWidget)

        self.login = QWidget()
        self.register = QWidget()
        self.home = QWidget()

        self.loginUI()
        self.homeUI()

        self.pages.addWidget(self.login)
        self.pages.addWidget(self.home)

    def loginUI(self):

        self.login_Layout = QGridLayout(self.login)

        self.login.setFixedSize(300, 200)

        self.loginButton = QPushButton("Log In")
        self.login_Layout.addWidget(self.loginButton, 0, 0)

    def homeUI(self):

        self.home_Layout = QGridLayout(self.home)

        self.home.setFixedSize(self.width, self.height)
        self.Button1 = QPushButton("Log Out")

        self.Button2 = QPushButton("HELLO")

        self.home_Layout.addWidget(self.Button1, 0, 0, 1, 1)
        self.home_Layout.addWidget(self.Button2, 0, 1)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            print("closed")

    def GoTohomePage(self):
        self.pages.setCurrentIndex(1)
    def GoTologinPage(self):
        self.pages.setCurrentIndex(0)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    M = Main()
    M.show()
    sys.exit(app.exec())

As you can see, I've incorporated the whole code in the same class, with some important modifications:如您所见,我已将整个代码合并到同一个类中,并进行了一些重要修改:

  • I created a new widget that is set as the central widget , which is almost mandatory for any QMainWindow class (to understand more about this, read the documentation about it);我创建了一个新的小部件,它被设置为中央小部件,这对于任何 QMainWindow 类几乎都是强制性的(要了解更多信息,请阅读有关它的文档);
  • the stacked layout is applied to the central widget;堆叠布局应用于中央小部件;
  • the window instance is explicitly shown (using M.show() )显式显示窗口实例(使用M.show()

With this simple modifications, the keyPressEvent is now correctly captured.通过这个简单的修改,现在可以正确捕获keyPressEvent Also consider that I tried to leave most of your code intact, but for what I can see you should use QStackedWidget instead, which behaves in the same ways, but, as a widget, it has better ways to control its contents:还要考虑到我试图保留您的大部分代码完整无缺,但就我所见,您应该使用 QStackedWidget 代替,它的行为方式相同,但是,作为小部件,它有更好的方法来控制其内容:

    def setupUI(self, Main):

        self.pages = QStackedWidget()
        self.setCentralWidget(self.pages)

        self.width = 900
        self.height = 500

        self.login = QWidget()
        self.register = QWidget()
        self.home = QWidget()

        self.loginUI()
        self.homeUI()

        self.pages.addWidget(self.login)
        self.pages.addWidget(self.home)
        # ...

Finally, if you want to use different window sizes for each "dialog" window, you shouldn't use a stacked based object at all, since it bases its size hint on the "biggest" widget it contains.最后,如果你想为每个“对话框”窗口使用不同的窗口大小,你根本不应该使用基于堆叠的对象,因为它的大小提示基于它包含的“最大”小部件。 If you don't want that, you could explicitly use self.setFixedSize(width, height) on the window each time the "page" changes, but I wouldn't suggest that.如果您不希望那样,您可以在每次“页面”更改时在窗口上明确使用self.setFixedSize(width, height) ,但我不建议这样做。

PS: I believe that you made the multiple inheritance mistake while trying to understand how the output of pyuic is used, or somehow misunderstanding the documentation about using Designer ; PS:我相信您在尝试了解如何使用pyuic的输出时犯了多重继承错误,或者以某种方式误解了有关使用 Designer的文档; maybe overzealous mistake, but an honest one ;-) .也许是一个过分的错误,但一个诚实的错误;-)。 I sincerely hope that nobody told you to create widgets like that... if that's the case, shame on him/her: that's completely wrong!我真诚地希望没有人告诉你创建这样的小部件......如果是这样的话,为他/她感到羞耻:那是完全错误的!

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

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