Jendela PyQt4 tertutup secara otomatis

Saya sedang mengerjakan aplikasi PyQt4 dan inilah yang saya miliki sejauh ini:

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

Masalah saya muncul ketika saya mencoba membuat mw kelas Jendela Utama. Untuk beberapa alasan ia akan melakukan MainWindow.initui() dan kemudian langsung menutupnya. Saya berasumsi ini ada hubungannya dengan fungsi main() dan objek QApplication. Apa cara terbaik untuk membuat kode banyak jendela dan mengatasinya? Saya awalnya akan membuat kelas per jendela: passwordPrompt, MainMenu dll dan kemudian membuat instance dari setiap kelas untuk memuat jendela baru tetapi seperti yang Anda lihat itu tidak berfungsi.


person WewLad    schedule 16.05.2016    source sumber
comment
Hai @WewLad, apakah menurut Anda salah satu jawaban bermanfaat? Semoga masalah Anda terpecahkan :-)   -  person K.Mulier    schedule 03.07.2016


Jawaban (3)


Saya telah mengubah sedikit kode Anda. Saya yakin ini berfungsi sekarang:

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

Saya menambahkan variabel tambahan ke kelas PasswordPrompt: variabel mySrc. Melalui mekanisme 'slot sinyal', saya menghubungkan variabel mySrc ke fungsi startMainWindow(passw). Jika Anda ingin membaca lebih lanjut tentang mekanisme slot sinyal, dan cara yang membantu Anda berkomunikasi dengan GUI dengan cara yang aman, lihat postingan ini:

Cara paling sederhana untuk PyQT Threading

Mungkin mekanisme slot sinyal agak berlebihan dalam situasi khusus ini, karena Anda tidak membuat thread lain. Tapi bagaimanapun, itu berhasil :-). Dalam fungsi startMainWindow(passw), saya membuat instance jendela utama. Setelah itu, saya menutup contoh prompt kata sandi. Sangat penting bahwa kedua contoh tersebut merupakan 'variabel global'. Jika jendela utama mw bukan variabel global, maka jendela tersebut akan dihapus (dan jendela segera ditutup) ketika fungsi startMainWindow(passw)keluar. Itu karena mw hanyalah variabel lokal dalam fungsi itu.

Saya harap ini membantu Anda. Tolong beri tahu saya jika solusi ini berhasil untuk Anda.

person K.Mulier    schedule 16.05.2016
comment
Saya mulai memahami hal ini, semakin saya memikirkannya. - person WewLad; 16.05.2016
comment
Bagus :-) Jika ada yang bisa saya bantu, beri tahu saya. - person K.Mulier; 16.05.2016
comment
Wow, saya baru saja mengubah variabel mw di kode asli saya menjadi global dan anehnya berfungsi. - person WewLad; 16.05.2016
comment
Ya, itulah masalahnya. Jika ini adalah variabel lokal, maka akan segera dihapus. Jika ini adalah variabel global, ia akan hidup selamanya :-) - person K.Mulier; 16.05.2016
comment
Itu juga yang saya sarankan dalam jawaban saya. Untuk menjadikan variabel-variabel itu global. Saya menambahkan mekanisme sinyal/slot sebagai bonus tambahan. Kalau-kalau Anda pernah bekerja dengan thread lain, dan Anda ingin mengirim sinyal/data ke GUI Anda. - person K.Mulier; 16.05.2016

Jadi saya membuat tinjauan singkat terhadap kode Anda. Saya juga mencoba melakukan hal serupa tetapi tidak berhasil juga. Yang saya buat adalah QDialog dan periksa DialogCode yang dikembalikan, jika diterima maka panggil 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()

Saya bukan ahli PyQt4 tetapi saya membuat beberapa aplikasi dengan pendekatan ini dan menurut saya itu sepenuhnya valid. Semoga bisa membantu!

person Szabolcs    schedule 16.05.2016

Memperbaikinya. Saya menginisialisasi variabel mw sebagai variabel global sebelum menugaskannya ke instance MainWindow(). Anehnya, hanya itu yang perlu saya lakukan.

person WewLad    schedule 16.05.2016
comment
Hai @WewLad, karena jawaban saya mengarahkan Anda ke arah yang benar, sedikit suara positif akan dihargai :-) - person K.Mulier; 16.05.2016