PyQt 窗口在打开后关闭

Posted

技术标签:

【中文标题】PyQt 窗口在打开后关闭【英文标题】:PyQt window closes after opening 【发布时间】:2016-09-14 05:35:28 【问题描述】:

我有两个文件,分别是main.pyclient_window.py。我想在进度条完成进度后显示客户端窗口。但我发现客户端窗口会立即打开和关闭。有人可以建议如何更改代码,以便我掌握正确的逻辑吗?

这是main.py

"""
This module defines the User Interface
"""

import sys
import time

from cloudL.ui import client_window

from PyQt4 import QtGui

from PyQt4 import QtCore
from PyQt4.QtGui import *


class ProgressBarWidget(QtGui.QDialog):

    def __init__(self, parent=None):
        super(ProgressBarWidget, self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)

        self.label = QLabel()
        self.tryAgain = QPushButton("Try Again")
        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setRange(0,100)
        self.tryAgain.setEnabled(False)

        layout.addWidget(self.label)
        layout.addWidget(self.progressBar)
        layout.addWidget(self.tryAgain)

        self.myLongTask = TaskThread()
        self.myLongTask.notifyProgress.connect(self.onProgress)
        self.myLongTask.start()

    def onStart(self):
        self.tryAgain.setEnabled(False)
        self.myLongTask.start()
        self.label.setText("")

    def onProgress(self, i):
        self.progressBar.setValue(i)
        if(self.progressBar.value() == 100):
            #app = QApplication(sys.argv)
            #global ex
            ex = client_window.main()
            ex.show()
            #ex.main()
            #ex.show()
            #sys.exit(app.exec_())
        else:
            self.tryAgain.setEnabled(True)
            self.tryAgain.clicked.connect(self.onStart)
            self.label.setText("Cannot connect to Server! Please Try Again!")


class TaskThread(QtCore.QThread):
    notifyProgress = QtCore.pyqtSignal(int)
    def run(self):
        for i in range(101):
            self.notifyProgress.emit(i)
            time.sleep(0.005)

class MainWindow(QWidget):
    """
    This window will be the first screen to appear
    """

    def __init__(self, parent = None):
        super(MainWindow, self).__init__(parent)
        """
        Initializes parameters required by the MainWindow
        """
        self.option = ""       # to specify the if the selected option is Server or Client
        self.ex = None

    def main(self):
        """
        This function is the origin where the initiation of the control takes place
        :return: Returns nothing
        """

        mainLayout = QVBoxLayout()
        mainLayout.setAlignment(QtCore.Qt.AlignCenter)

        radioLayout = QHBoxLayout()
        mainLayout.setAlignment(QtCore.Qt.AlignCenter)

        label = QLabel()
        label.setText("Select whether to act as a Server or a Client")
        labelFont = QFont()
        labelFont.setBold(True)
        labelFont.setPointSize(15)
        label.setFont(labelFont)

        mainLayout.addWidget(label)
        mainLayout.addStretch()

        b1 = QRadioButton("Server")
        b1.setChecked(True)
        b1.toggled.connect(lambda : btnstate(b1))
        radioLayout.addWidget(b1)

        b2 = QRadioButton("Client")
        b2.toggled.connect(lambda : btnstate(b2))
        radioLayout.addWidget(b2)

        self.option = ""

        def btnstate(b):
            """
            Nested function to define the action when radio button is toggled
            :param b: Button which is toggled currently
            :return: Returns nothing
            """
            if b.text() == "Server" and b.isChecked() == True:
                self.option = "Server"

            if b.text() == "Client" and b.isChecked() == True:
                self.option = "Client"

        start = QPushButton("Start")

        mainLayout.addLayout(radioLayout)
        mainLayout.addStretch()
        mainLayout.addWidget(start)

        self.setLayout(mainLayout)
        self.setGeometry(400, 200, 300, 300)
        self.setWindowTitle("CloudL")

        start.clicked.connect(self.showdialog)

    def showdialog(self):
        """
        A sample message box to check and display which option is chosen
        :return: Returns nothing
        """
        #app = QApplication(sys.argv)
        self.ex = ProgressBarWidget(self)
        self.ex.setGeometry(400, 200, 500, 150)
        self.destroy()
        self.ex.setWindowTitle("CloudL")
        self.ex.show()


"""
Execute the required action
"""
app = QApplication(sys.argv)
ex = MainWindow()
ex.main()
ex.show()
sys.exit(app.exec_())

client_window.py如下:

#client_window.py

import sys
from PyQt4 import QtCore

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class myListWidget(QListWidget):
    def Clicked(self, item):
        QMessageBox.information(self, "ListWidget", "You clicked: " + item.text())


class Example(QWidget):
    def __init__(self):
        super(Example, self).__init__()
        self.listWidget = None
        self.initUI()

    def initUI(self):
        hbox = QHBoxLayout(self)

        topleftLayout = QVBoxLayout()
        topleftLayout.setAlignment(QtCore.Qt.AlignTop)
        topleft = QFrame()
        topleft.setFrameShape(QFrame.StyledPanel)
        label = QLabel()
        label.setText("SERVER LIST")
        label.setAlignment(QtCore.Qt.AlignCenter)
        topleftLayout.addWidget(label)
        self.addServerList(topleftLayout)
        topleft.setLayout(topleftLayout)
        bottom = QFrame()
        bottom.setFrameShape(QFrame.StyledPanel)

        splitter1 = QSplitter(Qt.Horizontal)
        textedit = QTextEdit()
        splitter1.addWidget(topleft)
        splitter1.addWidget(textedit)
        splitter1.setSizes([100, 200])

        splitter2 = QSplitter(Qt.Vertical)
        splitter2.addWidget(splitter1)
        splitter2.addWidget(bottom)
        splitter2.setSizes([225, 100])

        hbox.addWidget(splitter2)

        self.setLayout(hbox)
        QApplication.setStyle(QStyleFactory.create('Cleanlooks'))

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('QSplitter demo')
        self.showMaximized()

    def addServerList(self, layout):
        self.listWidget = myListWidget()
        self.listWidget.resize(300, 120)

        self.listWidget.addItem("Item 1");
        self.listWidget.addItem("Item 2");
        self.listWidget.addItem("Item 3");
        self.listWidget.addItem("Item 4");

        self.listWidget.setWindowTitle('PyQT QListwidget Demo')
        self.listWidget.itemClicked.connect(self.listWidget.Clicked)
        layout.addWidget(self.listWidget)


def main():
    ex = Example()
    ex.showMaximized()
    return ex


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main()
    sys.exit(app.exec_())

我正在拨打client_window 的电话:

def onProgress(self, i):
    self.progressBar.setValue(i)
    if(self.progressBar.value() == 100):
        #app = QApplication(sys.argv)
        #global ex
        ex = client_window.main()
        ex.show()
        #ex.main()
        #ex.show()
        #sys.exit(app.exec_())
    else:
        self.tryAgain.setEnabled(True)
        self.tryAgain.clicked.connect(self.onStart)
        self.label.setText("Cannot connect to Server! Please Try Again!")

另外,如果我在客户端窗口中包含 app = QApplication(sys.argv)sys.exit(app.exec_()) 行,我会收到以下错误:

QCoreApplication::exec: 事件循环已经在运行 pyqt 错误

【问题讨论】:

要在 PyQt 中打开一个窗口,您必须在创建和显示小部件之前拥有 app = QtGui.QApplication(sys.argv)。我不知道具体原因,但您可以使用 this 网站作为参考(它对我有用......)祝你好运 这能回答你的问题吗? PyQt: Why does new window close immediately after opening it 【参考方案1】:

您需要保留对客户端窗口的引用,否则它将在onProgress 返回时立即被垃圾回收:

def onProgress(self, i):
    self.progressBar.setValue(i)
    if self.progressBar.value() == 100:
        self.client_window = client_window.main()
    else:
        self.tryAgain.setEnabled(True)
        self.tryAgain.clicked.connect(self.onStart)
        self.label.setText("Cannot connect to Server! Please Try Again!")

【讨论】:

以上是关于PyQt 窗口在打开后关闭的主要内容,如果未能解决你的问题,请参考以下文章

PyQt 窗口在打开后立即关闭

窗口关闭后 PyQt 线程仍在运行

PyQt QWidget 窗口在显示后立即关闭?

在 PyQt5 中打开一个窗口和关闭一个窗口

如何使用 PyQt 在窗口中切换布局? (不关闭/打开窗口)

按下保存按钮pyqt5后关闭第二个小部件