【问题标题】:emitting signal when python thread finishes to close the Qt Gu that initiated the thread当python线程完成关闭启动线程的Qt Gu时发出信号
【发布时间】:2014-08-07 07:36:12
【问题描述】:

我试图在 python 线程完成运行时发出一个信号,所以当它完成时,发出的信号会关闭启动线程的 PYQT 窗口。

在代码中见 cmets。

import sys
import threading
from PyQt4 import QtGui, QtCore

class MyThread(threading.Thread):
    """ docstring for MyThread
    """
    def __init__(self, job_done, settings):
        super(MyThread, self).__init__()
        self._Settings = settings

    def run(self):
        while not job_done.is_set():
            if not processSetting(self._Settings):
                raise Exception("Could not process settings")
            else:
                ## Emit Signal
                pass


class MyWindow(QtGui.QWidget):
    """docstring for MyWindow"""
    def __init__(self, settings, parent=None):
        super(MyWindow, self).__init__(parent)
        self._Settings = settings
        self._job_done = threading.Event()
        self._myThread = MyThread(self._job_done, self._Settings)
        ## catch the signal to close this window.

    def closeEvent(self, event):
        if self._myThread.isAlive():
            reply=QtGui.QMessageBox.question(self, "Are you sure to quit?","Settings are getting applied !!!",QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
            if reply==QtGui.QMessageBox.Yes:
                event.accept()
            else:
                event.ignore()


def processSettings():
    print "processSettings() Called"
    return True

def main():
    app = QtGui.QApplication(sys.argv)
    main = MyWindow()
    main.show()
    sys.exit(app.exec_())

在上面的代码中,我想在 processSttingts 返回 True 时发出信号 然后 MyWindow 应该关闭。

编辑这是我尝试做的。

所以我的目标是在processSettings 返回True 并关闭QMainWindow MyWindow 时发出信号。 导入系统 导入线程 从 PyQt4 导入 QtGui,QtCore

def processSettings():
    print "processSettings() Called"
    return True


class MyThread(threading.Thread):
    """ docstring for MyThread
    """
    def __init__(self, settings):
        super(MyThread, self).__init__()
        self._Settings = settings
        self.signal = QtCore.SIGNAL("signal")
        self._job_done = threading.Event()

    def run(self):
        # while not job_done.is_set():
        print "in thread"
        if not processSettings():
            raise Exception("Could not process settings")
        else:
            QtCore.emit(self.signal, "hi from thread")

class MyWindow(QtGui.QMainWindow):
    """docstring for MyWindow"""
    def __init__(self, settings, parent=None):
        super(MyWindow, self).__init__(parent)
        self._Settings = settings
        self._myThread = MyThread(self._Settings)
        self._myThread.daemon = False
        self._myThread.start()
        self.connect(self._myThread, self._myThread.signal, self.testfunc)


    def closeEvent(self, event):
        if self._myThread.isAlive():
            reply=QtGui.QMessageBox.question(self, "Are you sure to quit?","Settings are getting applied !!!",QtGui.QMessageBox.Yes,QtGui.QMessageBox.No)
            if reply==QtGui.QMessageBox.Yes:
                event.accept()
            else:
                event.ignore()

    def testfunc(self, sigstr):
        """ Purpose of this function is to close this window"""
        print sigstr
        self.close()



def main():
    app = QtGui.QApplication(sys.argv)
    settings = {'test': True}
    wind = MyWindow(settings)
    wind.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    sys.exit(main()) 

【问题讨论】:

  • 您是否尝试发出信号? QThreads 和其他的 QObjects 一样。我想你明白了,你只需要这样做。
  • 问题是我在做哪个项目,我必须避免使用 QThreads。
  • 你有没有尝试在你的 Python 线程中放置一个 QObject,从这个 QObject 发出并从 MyWindow 连接到这个 QObject?
  • 能否请您显示您想说的内容我已经更新了上面的编辑.. 而不是 QtCore 我尝试使用 self 但这没有意义,因为 threading.Thread 对象没有' t 有发射功能,所以现在我只需要发射QtSignal

标签: python multithreading qt


【解决方案1】:

这是我在 cmets 中提出的解决方案的一个示例:

from PyQt4 import QtGui, QtCore
import threading
import time

class MyThread(threading.Thread):
    def __init__(self, *args):
        threading.Thread.__init__(self, *args)

        self.job_done = threading.Event()
        self.qt_object = QtCore.QObject()

    def end_job(self):
        self.job_done.set()

    def run(self):
        while not self.job_done.is_set():
            time.sleep(1)

        QtCore.QObject.emit(self.qt_object, QtCore.SIGNAL("job_done"))


th = MyThread()
th.start()

app = QtGui.QApplication([])

w = QtGui.QWidget()
btn = QtGui.QPushButton('click me to exit', w)
QtGui.QVBoxLayout(w)
w.layout().addWidget(btn)

def btn_clicked():
    th.end_job()

QtCore.QObject.connect(btn, QtCore.SIGNAL("clicked()"), btn_clicked)

QtCore.QObject.connect(th.qt_object, QtCore.SIGNAL("job_done"), w.close)

w.show()

app.exec_()

【讨论】:

    【解决方案2】:

    您需要确保解决方案是线程安全的,并且将 python 线程发出的信号直接连接到 QT 线程中的插槽不是线程安全的。 mguijarr 在他对“Emit signal in standard python thread”的回答中提出的 SafeConnector 类可能很有用。我成功地使用了他使用管道而不是套接字的解决方案的修改版本:

    class SafeConnector(object):
        """Share between Python thread and a Qt thread.
    
        Qt thread calls :meth:`connect` and the python thread calls :meth:`emit`.
        The slot corresponding to the emitted signal will be called in Qt's
        thread.
        """
        def __init__(self):
            self._fh_read, self._fh_write = os.pipe()
            self._queue = Queue.Queue()
            self._qt_object = QtCore.QObject()
            self._notifier = QtCore.QSocketNotifier(self._fh_read,
                                                    QtCore.QSocketNotifier.Read)
            self._notifier.activated.connect(self._recv)
    
        def close(self):
            del self._qt_object
            self._qt_object = None
            os.close(self._fh_read)
            os.close(self._fh_write)
            self._fh_read, self._fh_write = None, None
    
        def connect(self, signal, receiver):
            """Connect the signal to the specified receiver slot.
    
            :param signal: The signal to connected.
            :param receiver: The receiver slot for the signal.
            """
            QtCore.QObject.connect(self._qt_object, signal, receiver)
    
        def emit(self, signal, *args):
            """Emit a Qt signal from a python thread.
    
            All remaning args are passed to the signal.
    
            :param signal: The Qt signal to emit.
            """
            self._queue.put((signal, args))
            os.write(self._fh_write, '!')
    
        def _recv(self):
            """Receive the signal from the Queue in Qt's main thread."""
            os.read(self._fh_read, 1)
            signal, args = self._queue.get()
            self._qt_object.emit(signal, *args)
    

    mguijarr 帖子中的示例使用任一实现都有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多