简体   繁体   中英

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. I believe I have added the right code, yet the keyPressEvent will not even register a key click. I have tried setting the focus using self.setFocusPolicy(Qt.StrongFocus) but it did not work. 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").

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.

What you're actually seeing is not your main window (the instance of Main ), but all the individual QWidgets you created ( self.login , etc.).

This is a "non-bug" (probably related to this report ): when a new widget is added to a QStackedLayout, it tries to show it. 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.

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

The solution is to implement everything in the Main class, create a central widget and set the stacked layout for that widget.

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

        
        # 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()
    
    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);
  • the stacked layout is applied to the central widget;
  • the window instance is explicitly shown (using M.show() )

With this simple modifications, the keyPressEvent is now correctly captured. 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:

    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.

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 ; 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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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