2

I've been working on a PyQt4 application and this is what I have so far:

 import sys
from PyQt4 import QtGui, QtCore

class PasswordPrompt(QtGui.QWidget):

    def __init__(self):
        super(PasswordPrompt, self).__init__()
        self.initUi()

    def initUi(self):
        self.setFixedSize(500, 75)
        self.setWindowTitle('Please enter the password...')

        self.prompt = QtGui.QLineEdit(self)
        self.btn = QtGui.QPushButton('Enter', self)
        self.btn.clicked.connect(self.btnClicked)

        self.hbox = QtGui.QHBoxLayout()
        self.hbox.addWidget(self.prompt)
        self.hbox.addWidget(self.btn)

        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addLayout(self.hbox)
        self.vbox2 = QtGui.QVBoxLayout()

        self.vbox2.addSpacing(300)
        self.hbox2 = QtGui.QHBoxLayout()
        self.hbox2.addSpacing(150)
        self.vbox2.addLayout(self.hbox2)

        self.vbox.addLayout(self.vbox2)

        self.setLayout(self.vbox)
        self.center()
        self.show()

    def btnClicked(self):
        pw = self.prompt.text()

        if pw == "password":
            print("Permission granted!")
            self.close()
            mw = MainWindow()

        else:
            print("Permissed denied!")
            self.prompt.clear()
            self.warningText = QtGui.QLabel('That is the wrong password!', self)
            self.hbox2.addWidget(self.warningText)

    def center(self):
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

class MainWindow(QtGui.QWidget):

    def __init__(self):
        super(MainWindow, self).__init__()
        self.initUi()

    def initUi(self):
        self.setWindowTitle('Main Menu')
        self.setFixedSize(1000, 800)

        self.show()

def main():
    application = QtGui.QApplication(sys.argv)
    p = PasswordPrompt()
    sys.exit(application.exec())


if __name__=='__main__':
    main()

My problem comes when I try to create mw of class Main Window. For some reason it will do MainWindow.initui() and then just close immediately. I assume it has something to do with the main() function and the QApplication object. What's the best way to code multiple windows and work around this? I was originally going to make a class per window: passwordPrompt, MainMenu etc and then instantiate an instance of each class to load a new window but as you can see it's not working.

WewLad
  • 717
  • 2
  • 11
  • 22

3 Answers3

0

I have tweaked your code a bit. I believe it works now:

import sys
import time
from PyQt4 import QtGui, QtCore

# Create two global variables:
p = None    
mw = None


# Create the class 'Communicate'. The instance
# from this class shall be used later on for the
# signal/slot mechanism.
class Communicate(QtCore.QObject):
    myGUI_signal = QtCore.pyqtSignal(str)

''' End class '''


class PasswordPrompt(QtGui.QWidget):

    def __init__(self):
        super(PasswordPrompt, self).__init__()
        self.initUi()
        self.mySrc = Communicate()
        self.mySrc.myGUI_signal.connect(startMainWindow) 

    def initUi(self):
        self.setFixedSize(500, 75)
        self.setWindowTitle('Please enter the password...')

        self.prompt = QtGui.QLineEdit(self)
        self.btn = QtGui.QPushButton('Enter', self)
        self.btn.clicked.connect(self.btnClicked)

        self.hbox = QtGui.QHBoxLayout()
        self.hbox.addWidget(self.prompt)
        self.hbox.addWidget(self.btn)

        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addLayout(self.hbox)
        self.vbox2 = QtGui.QVBoxLayout()

        self.vbox2.addSpacing(300)
        self.hbox2 = QtGui.QHBoxLayout()
        self.hbox2.addSpacing(150)
        self.vbox2.addLayout(self.hbox2)

        self.vbox.addLayout(self.vbox2)

        self.setLayout(self.vbox)
        self.center()
        self.show()

    def btnClicked(self):
        pw = self.prompt.text()

        if pw == "password":
            print("Permission granted!")
            # self.close()
            self.mySrc.myGUI_signal.emit("password")


        else:
            print("Permissed denied!")
            self.prompt.clear()
            self.warningText = QtGui.QLabel('That is the wrong password!', self)
            self.hbox2.addWidget(self.warningText)

    def center(self):
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

''' End class '''


class MainWindow(QtGui.QWidget):

    def __init__(self):
        super(MainWindow, self).__init__()
        self.initUi()

    def initUi(self):
        self.setWindowTitle('Main Menu')
        self.setFixedSize(1000, 800)

        self.show()

''' End class '''

def main():
    global p
    application = QtGui.QApplication(sys.argv)
    p = PasswordPrompt()
    sys.exit(application.exec())

def startMainWindow(passw):
    global mw
    global p
    if(passw == "password"):
        mw = MainWindow()
        p.close()
    else:
        pass


if __name__=='__main__':
    main()

I added an extra variable to the PasswordPrompt class: the mySrc variable. Through the so called 'signal slot' mechanism, I connect the mySrc variable to the function startMainWindow(passw). If you want to read more about the signal slot mechanism, and the ways it helps you to communicate with GUI's in a thread-safe way, check out this post:

Simplest way for PyQT Threading

Maybe the signal-slot mechanism is a bit overkill in this particular situation, because you're not creating other threads. But anyway, it works :-). In the function startMainWindow(passw), I create the main window instance. After that, I close down the password prompt instance. It is vital that both instances are 'global variables'. If the main window mw is not a global variable, it gets deleted (and the window closes down immediately) when the function startMainWindow(passw)exits. That's because mw is only a local variable in that function.

I hope this helped you out. Please let me know if this solution works for you.

Community
  • 1
  • 1
K.Mulier
  • 8,069
  • 15
  • 79
  • 141
  • I'm beginning to understand this the more I go over it I think. – WewLad May 16 '16 at 18:06
  • Great :-) If there is anything I can help you with, please let me know. – K.Mulier May 16 '16 at 18:10
  • Wow, I just changed the mw variable in my original code to global and it worked strangely enough. – WewLad May 16 '16 at 18:17
  • Yeah, that is the problem. When it is a local variable, it gets deleted soon. When it is a global variable, it lives forever :-) – K.Mulier May 16 '16 at 18:19
  • That's also what I suggested in my answer. To make those variables global. I added the signal/slot mechanism as an extra bonus. Just in case you would ever work with other threads, and you want to send signals / data to your GUI. – K.Mulier May 16 '16 at 18:20
0

So I made a quick review of your code. I also tried to do something similar but it didn't work for me either. What I made instead is a QDialog and check its returned DialogCode, if accepted then call the MainWindow.

import sys
from PyQt4 import QtGui, QtCore

class PasswordPrompt(QtGui.QDialog):

    def __init__(self):
        super(PasswordPrompt, self).__init__()
        self.initUi()

    def initUi(self):
        self.setFixedSize(500, 75)
        self.setWindowTitle('Please enter the password...')

        self.prompt = QtGui.QLineEdit(self)
        self.btn = QtGui.QPushButton('Enter', self)
        self.btn.clicked.connect(self.btnClicked)

        self.hbox = QtGui.QHBoxLayout()
        self.hbox.addWidget(self.prompt)
        self.hbox.addWidget(self.btn)

        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addLayout(self.hbox)
        self.vbox2 = QtGui.QVBoxLayout()

        self.vbox2.addSpacing(300)
        self.hbox2 = QtGui.QHBoxLayout()
        self.hbox2.addSpacing(150)
        self.vbox2.addLayout(self.hbox2)

        self.vbox.addLayout(self.vbox2)

        self.setLayout(self.vbox)
        self.center()

    def btnClicked(self):
        pw = self.prompt.text()

        if pw == "password":
            print("Permission granted!")
            self.accept()

        else:
            print("Permissed denied!")
            self.prompt.clear()
            self.warningText = QtGui.QLabel('That is the wrong password!', self)
            self.hbox2.addWidget(self.warningText)

    def center(self):
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

class MainWindow(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.initUi()

    def initUi(self):
        self.setWindowTitle('Main Menu')
        self.setFixedSize(1000, 800)

        self.show()

def main():
    application = QtGui.QApplication(sys.argv)
    p = PasswordPrompt()
    if p.exec_() == QtGui.QDialog.Accepted:
        mw = MainWindow()
    sys.exit(application.exec_())


if __name__=='__main__':
    main()

I'm not an expert of PyQt4 but I made some apps with this approach and I think it's totally valid. Hope it helps!

Szabolcs
  • 3,990
  • 18
  • 38
0

Fixed it. I initialized the mw variable as a global variable before assigning it to an instance of MainWindow(). That's all I needed to do strangely.

WewLad
  • 717
  • 2
  • 11
  • 22
  • Hi @WewLad , since my answer tipped you in the right direction, a little upvote would be appreciated :-) – K.Mulier May 16 '16 at 18:37