无法从线程显示窗口

时间:2014-02-03 11:06:41

标签: python multithreading pyqt pyqt4

我有几个需要使用窗口的线程。这是线程定义:

class MyThread(QtCore.QThread):
    def __init__(self, id, window, mutex):
        super(MyThread, self).__init__()
        self.id = id
        self.window = window
        self.mutex = mutex
        self.connect(self, QtCore.SIGNAL("load_message_input()"), self.window, QtCore.SLOT("show_input()"))

    def run(self):
        self.mutex.lock()
        self.emit(QtCore.SIGNAL("load_message_input()"))
        self.connect(self.window, QtCore.SIGNAL("got_message(QString)"), self.print_message)
        self.window.input_finished.wait(self.mutex)
        self.mutex.unlock()

    def print_message(self, str):
        print "Thread %d: %s" % (self.id, str)

这里是窗口定义:

class MyDialog(QtGui.QDialog):
    def __init__(self, *args, **kwargs):
        super(MyDialog, self).__init__(*args, **kwargs)
        self.last_message = None

        self.setModal(True)
        self.message_label = QtGui.QLabel(u"Message")
        self.message_input = QtGui.QLineEdit()
        self.dialog_buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)
        self.dialog_buttons.accepted.connect(self.accept)
        self.dialog_buttons.rejected.connect(self.reject)
        self.hbox = QtGui.QHBoxLayout()
        self.hbox.addWidget(self.message_label)
        self.hbox.addWidget(self.message_input)
        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addLayout(self.hbox)
        self.vbox.addWidget(self.dialog_buttons)
        self.setLayout(self.vbox)

        self.input_finished = QtCore.QWaitCondition()

    @QtCore.pyqtSlot()
    def show_input(self):
        self.exec_()

    def on_accepted(self):
        self.emit(QtCore.SIGNAL("got_message(QString)"), self.message_input.text())
        self.input_finished.wakeOne()

这是主要的:

if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)

    mutex = QtCore.QMutex()
    threads = []
    window = test_qdialog.MyDialog()

    for i in range(5):
        thread = MyThread(i, window, mutex)
        thread.start()
        threads.append(thread)

    for t in threads:
        t.wait()

    sys.exit(app.exec_())

我无法弄清楚为什么在执行脚本时不显示窗口。

更新: 由于某种原因,其他线程不会与self.mutex.lock()保持联系。无法弄清楚原因。

2 个答案:

答案 0 :(得分:1)

您的代码中有几个问题:

  • 如果您希望QThread使用广告位,则需要为其创建事件循环(这很简单,只需致电QThread.exec_),但{{1}带有事件循环的问题需要以不同的方式编码(接下来我会给你发一个例子)
  • 如果要发出消息,则需要将QThread连接到on_accepted,除非您使用Qt的自动连接功能。
  • 如果您想首先使用accepted,则需要启动QThread,以便在调用QApplication之前无法执行for t in threads: t.wait()(在我的示例中刚删除)它)。
  • 最后但并非不太重要的问题:如果您希望线程专门使用资源,您应该考虑使用消费者 - 生产者方法(问题是当您发出信号时,每个插槽都会获得数据的副本,如果你试图阻止一个带有事件循环的线程,应用程序只是冻结,解决消费者 - 生产者的问题我将一个额外的互斥量传递给消息的信号,尝试来锁定它[永远不会阻塞! ]知道线程是否消耗了事件)

正如所承诺的,有一个如何在QApplication.exec_上使用事件循环的例子:

QThread

注意:几乎总是首先接收信号的线程将是id为1的线程。

我的建议是,不要在线程中使用插槽(这样可以安全地使用互斥和等待条件)并为消息实现消费者 - 生产者方法。

答案 1 :(得分:0)

在调用app.exec_()之前,您正在等待线程退出。您可能应该监视GUI空闲循环中的线程或连接到线程的finished()信号。