PyQt5 Login to Register Dialog Auto Close

Viewed 271

I have a login and register dialog, and of course a main window. So, I want the users to be able to switch between login and register dialog, and if the user enters correct credentials, the user can go to the main window. If the user registered a new credential, then the user will be redirected to the login window. That said, the first interface that the user see is the login dialog. Here are some codes for login-register dialog:

class Login(QDialog):
    # Push Button -> Login
    # Push Button 2 -> To Register
    # Push Button 3 -> Exit
    def __init__(self):
        super(Login, self).__init__()
        # Load Login UI
        loadUi("Login.ui", self)
        # Set Translucent Background for the Windows
        self.setWindowFlags(PyQt5.QtCore.Qt.FramelessWindowHint)
        self.setAttribute(PyQt5.QtCore.Qt.WA_TranslucentBackground)
        # Set Push Button 1 to call the function upon clicked
        self.pushButton.clicked.connect(self.check_login)
        # Set Push Button 2 to call the function upon clicked
        self.pushButton_2.clicked.connect(self.redirect_to_register)
        # Set Push Button 3 to call the function upon clicked
        self.pushButton_3.clicked.connect(self.close_window)
        # Show the Window
        self.show()

    # Procedure to redirect to register windows
    def redirect_to_register(self):
        self.close()  # Close the login windows
        # Show the register windows
        self.register = Register()
        self.register.show()
...

class Register(QDialog):
    # Push Button -> Register
    # Push Button 2 -> To Login
    # Push Button 3 -> Exit
    def __init__(self):
        # Load Register UI
        super(Register, self).__init__()
        loadUi("Register.ui", self)
        # Set Translucent Background for the Windows
        self.setWindowFlags(PyQt5.QtCore.Qt.FramelessWindowHint)
        self.setAttribute(PyQt5.QtCore.Qt.WA_TranslucentBackground)
        # Set Push Button 2 to call the function upon clicked
        self.pushButton.clicked.connect(self.insert_to_database)
        # Set Push Button 2 to call the function upon clicked
        self.pushButton_2.clicked.connect(self.redirect_to_login)
        # Set Push Button 3 to call the function upon clicked
        self.pushButton_3.clicked.connect(self.close_window)
        # Show the Window
        self.show()

    # Procedure to redirect to login windows
    def redirect_to_login(self):
        # Close the login windows
        self.close()
        # Show the register windows
        self.login = Login()
        self.login.show()

    def close_window(self):
        self.close()

I load the .ui file of both dialog. But, for the main window, the .py file is converted from the .ui file. That said, in the main of the login file, I call the main window with this code:

import GoodLife
# Call main
if __name__ == "__main__":
    # Init App
    app = QApplication(sys.argv)
    QtGui.QFontDatabase.addApplicationFont("../img/dripicons-v2.ttf")
    # Build the window
    window = Login()
    if(window.exec_() == QDialog.Accepted):
        GoodLife = QMainWindow()
        ui = Ui_MainWindow()
        ui.setupUi(GoodLife)
        GoodLife.setWindowTitle("Good Life - Your Dear Bestfriend :)")
        GoodLife.setWindowIcon(QtGui.QIcon('../img/goodlife.jpg'))
        GoodLife.show()
        sys.exit(app.exec_())

With that code, I am able to go into the main window after logging in. But, whenever I tried to switch to register dialog, the register dialog keeps auto-closing. I believe that the line sys.exit(app.exec_()) is the cause of it, because when I unindent the line once, I can go to the register, but not the main window. Can anyone help me on this?

1 Answers

The problem is that when a dialog is closed, it exits its event loop (the one launched with exec) with a Rejected result.

In your case, since the rejection doesn't match window.exec_() == QDialog.Accepted, the result is that that whole block is not evaluated, and the application simply exits.

A simple solution would be to hide the login until the registration is completed (or rejected) and show it again afterwards.

Since the login dialog should be shown anyway, there's no need for custom signals or if statements, as it's enough to call the registration dialog's exec_ in the redirect_to_register function, so that you can show again the login no matter the result of the registration.

Unfortunately, there's a problem with that: in Qt, hiding a dialog results in a behavior similar to closing it (so, rejecting).
The solution is to avoid the base implementation of QDialog (which overrides both hide() and setVisible()), and use that of QWidget instead:

   def redirect_to_register(self):
        QtWidgets.QWidget.setVisible(self, False)
        self.register = Register()
        self.register.exec_()
        self.show()

This also means that in the register dialog you should not try to recreate the login window:

class Register(QDialog):
    def __init__(self):
        # ...
        self.pushButton_2.clicked.connect(self.accept)

Some unasked suggestions:

  • in the last code you're importing "GoodLife", then not only you're not using it, but you're also overwriting it as a variable; you probably did some copy/paste/edit error, but the point is that names that begin with uppercase letters should only be used for classes and constants, not for variables;
  • there's no need to implement a close_window function if it just calls self.close(): just connect signals to self.close;
  • be more verbose with object names, including widgets you create in Designer: having lots of pushButton_x is never a good idea, as you cannot easily distinguish their role;
  • commenting should be limited to sections in which it's not immediate what the code does; comments like "Set Push Button 2 to call the function upon clicked" or "Show the window" are completely useless and distracting as they don't add any information;
  • window title and icons can be set in Designer;
  • be careful with relative paths, especially for parent (../) folders; consider using Qt resource systems (which also allows you to set icons and images directly in Designer);
Related