Python 从多处理进程更新PySide GUI
我正在尝试创建一个通过多处理过程更新的PySide GUI,例如一个PySide GUI,它在一个窗口中显示文本,该窗口在一些计算之后更新。通过使用QThread,我能够毫无问题地更新GUI。但是,如果我尝试使用多处理进程而不是QThread(参见sys.exit之前的两行代码)执行相同的操作,我会得到一个错误。下面是一个简单的例子:Python 从多处理进程更新PySide GUI,python,user-interface,multiprocessing,pyside,python-multiprocessing,Python,User Interface,Multiprocessing,Pyside,Python Multiprocessing,我正在尝试创建一个通过多处理过程更新的PySide GUI,例如一个PySide GUI,它在一个窗口中显示文本,该窗口在一些计算之后更新。通过使用QThread,我能够毫无问题地更新GUI。但是,如果我尝试使用多处理进程而不是QThread(参见sys.exit之前的两行代码)执行相同的操作,我会得到一个错误。下面是一个简单的例子: import sys from PySide import QtCore, QtGui from multiprocessing import Process i
import sys
from PySide import QtCore, QtGui
from multiprocessing import Process
import time
class GUI(QtGui.QMainWindow):
def __init__(self):
super(GUI, self).__init__()
self.initUI()
def initUI(self):
self.text = "normal text"
self.setGeometry(300, 300, 500, 300)
self.setWindowTitle('TestGUI')
self.show()
def paintEvent(self, event):
qp = QtGui.QPainter()
qp.begin(self)
self.drawText(event, qp)
qp.end()
def drawText(self, event, qp):
qp.setPen(QtGui.QColor(0,0,0))
qp.setFont(QtGui.QFont('Decorative', 50))
qp.drawText(event.rect(), QtCore.Qt.AlignCenter, self.text)
@QtCore.Slot(str)
def setText(self, text):
self.text = text
print self.text
self.repaint()
class Communicate(QtCore.QObject):
updateGUI = QtCore.Signal(str)
class MyThread(QtCore.QThread):
def __init__(self, com):
super(MyThread, self).__init__()
self.com = com
def run(self):
count = 0
while True:
self.com.updateGUI.emit("update %d" % count)
count += 1
time.sleep(1)
def loopEmit(com):
while True:
com.updateGUI.emit(time.ctime())
time.sleep(1)
# Create and show GUI
app = QtGui.QApplication(sys.argv)
gui = GUI()
gui.show()
# connect signal and slot properly
com = Communicate()
com.updateGUI.connect(gui.setText)
thread = MyThread(com)
thread.start() # this works fine
time.sleep(0.5)
p = Process(target=loopEmit, args=[com])
p.start() # this breaks
sys.exit(app.exec_())
问题是GUI显然只能从主进程进行操作,因此尝试从新进程进行操作会引发以下错误:
The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.
我的直接反应是——只需在QThread中运行计算。但是计算本身相当繁重,所以我真的需要在一个单独的进程(和核心)中运行它。谢谢 另一个建议可能是使用Qt/PySide信号系统来完全避免任何类型的阻塞 这个示例用于让用户无需等待就可以从数据库中编辑或获取数据的耗时过程,但用户希望UI在可用后立即更新 下面是一个例子。虽然没有要显示的测试ui或测试数据,但示例显示了一个QT线程类,该类被设置为在数据准备好在调用应用程序中显示或使用时发出信号
import pprint
try:
from PySide import QtCore
except:
from PySide2 import QtCore
from custom_module import DATABASE
from ui.data_widget import DataWidget
class BatchThread(QtCore.QThread):
"""
Process the list of database batch queries as a threaded process and emit list when
complete.
Or you could have the run process constantly emit signals if it is a looping process
you want to keep signaling it is processing.
"""
sig = QtCore.Signal(list)
def __init__(self, parent=None):
QtCore.QThread.__init__(self, parent)
self.data = {}
def run(self):
try:
result = DATABASE.batchProcess(self.data)
self.sig.emit(result)
except:
self.sig.emit([])
def executing_script(data=[]):
"""
Main app that would have the UI elements you would want to update.
"""
# Assumption you have setup a textEdit widget called self.ui.displayWidget
def __init__(self, given_args=[]):
QtWidgets.QMainWindow.__init__(self, parent=None)
self.ui = DataWidget()
self.ui.setupUi(self)
# Create an instance of the independent process.
self.async_process = BatchThread(self)
# Connect the sig signal to a function to execute when the result is emitted.
self.async_process.sig.connect(self.display_result)
# Set the instance with data to process.
self.async_process.data = ['<data to process you dont want to wait on>']
# Start it processing the data.
self.async_process.run()
# Script execution continues.
def display_result(self, result=[]):
"""
When the process is finished, display it's result.
Since your instance signal emits a list, that is what will be received along with the call to the function.
"""
self.ui.displayWidget.clear()
self.ui.displayWidget.append(str(pprint.pprint(result)))
导入pprint
尝试:
从PySide导入QtCore
除:
从PySide2导入QtCore
从自定义模块导入数据库
从ui.data\u小部件导入数据小部件
类BatchThread(QtCore.QThread):
"""
将数据库批处理查询列表作为线程处理,并在
完成
或者,如果运行进程是循环进程,则可以让它不断发出信号
您希望不断发出它正在处理的信号。
"""
sig=QtCore.信号(列表)
def uuu init uuu(self,parent=None):
QtCore.QThread.\uuuuu init\uuuuu(self,parent)
self.data={}
def运行(自):
尝试:
结果=DATABASE.batchProcess(self.data)
自信号发射(结果)
除:
self.sig.emit([])
def正在执行_脚本(数据=[]):
"""
包含您想要更新的UI元素的主应用程序。
"""
#假设您已经设置了一个名为self.ui.displayWidget的文本编辑小部件
定义初始化(self,给定参数=[]):
qtwidts.QMainWindow.\uuuuu init\uuuuuu(self,parent=None)
self.ui=DataWidget()
self.ui.setupUi(self)
#创建独立进程的实例。
self.async_进程=批处理线程(self)
#将sig信号连接到一个函数,以便在发出结果时执行。
self.async\u process.sig.connect(self.display\u结果)
#使用要处理的数据设置实例。
self.async_process.data=['']
#开始处理数据。
self.async_process.run()
#脚本继续执行。
def显示结果(自身,结果=[]):
"""
流程完成后,显示其结果。
由于您的实例信号会发出一个列表,因此将随函数调用一起接收该列表。
"""
self.ui.displayWidget.clear()
self.ui.displayWidget.append(str(pprint.pprint(result)))
这不是你要找的吗?是的,看起来是的,谢谢!(在发布这篇文章之前,我搜索了一段时间,但没有找到答案)。然而,我发现,如果我给它一个类方法,apply_async就不起作用,只有当该方法是在类定义之外定义的时候。但对于锁定/阻塞来说,这可能是一个不同的问题。是的,谢谢,你已经回答了我的问题。更多的搜索表明实例方法是不“可pickle”的,因此不能传递给apply\u async(它使用pickle传递对象)。解决方案是在模块的顶层(即类外)定义方法,如中所述,或者“添加基础结构”以允许对这些方法进行pickle处理,如下所述