暂停当前​​功能,直到对话框关闭

Sea*_*ene 3 python qt pyqt

该示例有两个窗口,MainFooMain应该在关闭Foo后更早地显示输入的值Foo

全图

代码如下:

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

class Main(QWidget):
    def __init__(self):
        super(Main, self).__init__()
        self.setupUI()

    def setupUI(self):
        self.label = QLabel('0')

        okBtn = QPushButton('Start Foo')
        okBtn.clicked.connect(self.startFoo)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.label)
        mainLayout.addWidget(okBtn)
        self.setLayout(mainLayout)

        self.setWindowTitle('Main')
        self.show()

    def startFoo(self):
        foo = Foo()
        # I want the function to suspend until Foo() is destroyed, so I can set label's text as what I input earlier in `Foo`
        self.label.setText(str(foo.edit.text()))


class Foo(QDialog):
    def __init__(self):
        super(Foo, self).__init__()
        self.setupUI()
        self.var = 0

    def setupUI(self):

        # QLineEdit
        self.edit = QLineEdit()

        # QPushButton
        okBtn = QPushButton('OK')
        okBtn.clicked.connect(self.setVar)

        # main layout
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.edit)
        mainLayout.addWidget(okBtn)
        self.setLayout(mainLayout)

        self.setWindowTitle('Foo')
        self.show()

    def setVar(self):
        self.var = self.edit.text()
        self.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = Main()
    app.exec_()
Run Code Online (Sandbox Code Playgroud)

注意这一部分:

def startFoo(self):
    foo = Foo()
    # I want the function to suspend until Foo() is closed, so I can set label's text as what I input earlier in `Foo`
    self.label.setText(str(foo.edit.text()))
Run Code Online (Sandbox Code Playgroud)

我希望函数在Foo()被销毁之前一直挂起,因此我可以将label的文本设置为之前在中输入的内容Foo。但是该应用只是继续运行,这使得self.label的文本完全空白(因为foo.edit.text()NoneFoo()启动时)。我试过添加QEventLoop这样的:

def startFoo(self):
    foo = Foo()

    loop = QEventLoop()
    foo.destroyed.connect(loop.quit)
    loop.exec_()

    self.label.setText(str(foo.edit.text()))
Run Code Online (Sandbox Code Playgroud)

也不行。那么该怎么做呢?

Dan*_*one 5

You need to use exec_ instead of show to display the Foo dialog. The difference is that while show simply display the dialog window, exec_ will execute it as modal, so you can interact only with that dialog while the UI thread is suspended until the dialog is closed.

import sys

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

class Main(QWidget):

    def __init__(self):
        super(Main, self).__init__()
        self.setupUI()

    def setupUI(self):
        self.label = QLabel('0')

        okBtn = QPushButton('Start Foo')
        okBtn.clicked.connect(self.startFoo)

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.label)
        mainLayout.addWidget(okBtn)
        self.setLayout(mainLayout)

        self.setWindowTitle('Main')

    def startFoo(self):
        foo = Foo()
        foo.exec_()
        self.label.setText(str(foo.edit.text()))


class Foo(QDialog):

    def __init__(self):
        super(Foo, self).__init__()
        self.setupUI()
        self.var = 0

    def setupUI(self):

        # QLineEdit
        self.edit = QLineEdit()

        # QPushButton
        okBtn = QPushButton('OK')
        okBtn.clicked.connect(self.setVar)

        # main layout
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.edit)
        mainLayout.addWidget(okBtn)
        self.setLayout(mainLayout)

        self.setWindowTitle('Foo')

    def setVar(self):
        self.var = self.edit.text()
        self.close()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = Main()
    ex.show()
    app.exec_()
Run Code Online (Sandbox Code Playgroud)

Also, but this is mostly a personal advice and not a general rule, it's better to call show and exec_ from outside the class implementing the widget. In this way you can differentiate the way a dialog window is shown (for example you can create a button to execute show and another one to display it modal by calling exec_.