当python线程完成以关闭启动线程的Qt Gu时发出信号

时间:2014-06-17 10:20:22

标签: python multithreading qt

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

代码中的

见评论。

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()) 

2 个答案:

答案 0 :(得分:1)

您需要确保解决方案是线程安全的,并且将从python线程发出的信号直接连接到QT线程中的插槽不是线程安全的。 mguijarr在对#34; 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的帖子中的示例使用任一实现都有效。

答案 1 :(得分:0)

以下是我在评论中提出的解决方案示例:

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_()