Окно PyQt4 закрывается автоматически

Я работаю над приложением PyQt4, и это то, что у меня есть до сих пор:

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

Моя проблема возникает, когда я пытаюсь создать mw класса Main Window. По какой-то причине он выполнит MainWindow.initui(), а затем сразу же закроется. Я предполагаю, что это как-то связано с функцией main() и объектом QApplication. Каков наилучший способ закодировать несколько окон и обойти это? Изначально я собирался создать класс для каждого окна: passwordPrompt, MainMenu и т. д., а затем создать экземпляр каждого класса для загрузки нового окна, но, как вы видите, это не работает.


person WewLad    schedule 16.05.2016    source источник
comment
Привет, @WewLad, тебе помог один из ответов? Надеюсь, ваша проблема решена :-)   -  person K.Mulier    schedule 03.07.2016


Ответы (3)


Я немного подправил ваш код. Я считаю, что это работает сейчас:

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

Я добавил дополнительную переменную в класс PasswordPrompt: переменную mySrc. Через так называемый механизм «сигнального слота» я подключаю переменную mySrc к функции startMainWindow(passw). Если вы хотите узнать больше о механизме сигнального слота и о том, как он помогает вам взаимодействовать с графическим интерфейсом потокобезопасным способом, ознакомьтесь с этим сообщением:

Самый простой способ многопоточности PyQT

Возможно, в данной конкретной ситуации механизм сигнальных слотов немного излишен, потому что вы не создаете другие потоки. Но в любом случае это работает :-). В функции startMainWindow(passw) я создаю экземпляр главного окна. После этого я закрываю экземпляр запроса пароля. Крайне важно, чтобы оба экземпляра были «глобальными переменными». Если главное окно mw не является глобальной переменной, оно удаляется (и окно немедленно закрывается) при выходе из функции startMainWindow(passw). Это потому, что mw является только локальной переменной в этой функции.

Я надеюсь, что это помогло вам. Пожалуйста, дайте мне знать, если это решение работает для вас.

person K.Mulier    schedule 16.05.2016
comment
Я начинаю понимать это, чем больше я думаю об этом. - person WewLad; 16.05.2016
comment
Отлично :-) Если есть что-то, чем я могу вам помочь, пожалуйста, дайте мне знать. - person K.Mulier; 16.05.2016
comment
Вау, я только что изменил переменную mw в своем исходном коде на глобальную, и это сработало достаточно странно. - person WewLad; 16.05.2016
comment
Да, это проблема. Когда это локальная переменная, она вскоре удаляется. Когда это глобальная переменная, она живет вечно :-) - person K.Mulier; 16.05.2016
comment
Это также то, что я предложил в своем ответе. Чтобы сделать эти переменные глобальными. В качестве дополнительного бонуса я добавил механизм сигнала/слота. На тот случай, если вы когда-нибудь будете работать с другими потоками и захотите отправлять сигналы/данные в свой графический интерфейс. - person K.Mulier; 16.05.2016

Итак, я сделал быстрый обзор вашего кода. Я тоже пытался сделать что-то подобное, но у меня тоже не получилось. Вместо этого я сделал QDialog и проверил его возвращенный DialogCode, если он принят, затем вызовите 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()

Я не эксперт PyQt4, но я сделал несколько приложений с таким подходом, и я думаю, что это абсолютно правильно. Надеюсь, поможет!

person Szabolcs    schedule 16.05.2016

Починил это. Я инициализировал переменную mw как глобальную перед тем, как назначить ее экземпляру MainWindow(). Это все, что мне нужно было сделать странно.

person WewLad    schedule 16.05.2016
comment
Привет @WewLad, так как мой ответ подсказал вам правильное направление, было бы полезно немного проголосовать :-) - person K.Mulier; 16.05.2016