我正在尝试在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())
答案 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_()