首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >无法从线程显示窗口

无法从线程显示窗口
EN

Stack Overflow用户
提问于 2014-02-03 11:06:41
回答 2查看 142关注 0票数 1

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

代码语言:javascript
复制
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)

下面是窗口定义:

代码语言:javascript
复制
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()

这是主要的:

代码语言:javascript
复制
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()。不知道为什么。

EN

回答 2

Stack Overflow用户

发布于 2014-02-03 16:48:40

您的代码中有几个问题:

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

正如承诺的那样,有一个如何在QThreads上使用事件循环的示例:

代码语言:javascript
复制
from PyQt4 import QtCore, QtGui

class MyThread(QtCore.QThread):

    load_message_input = QtCore.pyqtSignal()

    def __init__(self, id, window):
        super(MyThread, self).__init__()
        self.id = id
        self.window = window
        self.load_message_input.connect(self.window.show_input)
        self.window.got_message.connect(self.print_message)
        self.started.connect(self.do_stuff)

    def run(self):
        print "Thread %d: %s" % (self.id,"running")
        self.exec_()

    @QtCore.pyqtSlot() 
    def do_stuff(self):
        print "Thread %d: %s" % (self.id,"emit load_message_input")
        self.load_message_input.emit()

    @QtCore.pyqtSlot("QString","QMutex")
    def print_message(self, msg, mutex):
        if mutex.tryLock():
            print "Thread %d: %s" % (self.id, msg)
        self.do_stuff()


class MyDialog(QtGui.QDialog):

    got_message = QtCore.pyqtSignal("QString","QMutex")    

    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.accepted.connect(self.on_accepted)
        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):
        print "showing input"
        window.show()
        window.setModal(True)    


    @QtCore.pyqtSlot()
    def on_accepted(self):
        print "emit: ", self.message_input.text()
        self.got_message.emit(self.message_input.text(), QtCore.QMutex())

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

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

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

    print "start app"
    sys.exit(app.exec_())

注意:通常情况下,最先接收信号的线程都是id 1的线程。

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

票数 1
EN

Stack Overflow用户

发布于 2014-02-03 16:48:58

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21525703

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档