Skip to main content
 首页 » 编程设计

Python:使用多处理池从外部函数更新小部件

2025年05月04日17bjzhanghao

如果您能告诉我为什么按下“确定”按钮不会更新 lineedit 文本字段,我将不胜感激。

from PyQt4 import QtCore, QtGui 
 
def externalFunc(arg): 
    print '\n\t Accessing lineedit from outside. Result   "', jobDialog.lineEdit.text(), '"   OK' 
    print "Attempting to change the lineEdit field to", arg 
    jobDialog.lineEdit.setText(arg) 
    print "...Completed." 
 
class MainWindow(QtGui.QMainWindow): 
    def __init__(self): 
        super(MainWindow, self).__init__() 
        self.main_layout = QtGui.QVBoxLayout() 
 
        self.lineEdit=QtGui.QLineEdit('Initial Text') 
        self.main_layout.addWidget(self.lineEdit) 
 
        ok_button = QtGui.QPushButton("OK") 
        ok_button.clicked.connect(self.OK) 
        self.main_layout.addWidget(ok_button)        
 
        central_widget = QtGui.QWidget() 
        central_widget.setLayout(self.main_layout) 
        self.setCentralWidget(central_widget) 
 
    def OK(self): 
        myList=['One','Two','Three'] 
        from multiprocessing import Pool 
        pool = Pool(processes=10) 
        try: pool.map_async( externalFunc, myList) 
        except Exception, e: print e 
 
if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
 
    jobDialog = MainWindow() 
    jobDialog.resize(480, 320) 
    jobDialog.show() 
    sys.exit(app.exec_()) 

另一个例子,这次有进度条。

这不仅仅是更新失败导致整个过程崩溃。同样的问题:为什么会发生以及如何解决。

from PyQt4 import QtCore, QtGui 
 
class PbWidget(QtGui.QProgressBar): 
    def __init__(self, parent=None, total=20): 
        super(PbWidget, self).__init__() 
        self.setMinimum(1) 
        self.setMaximum(total)         
        self._active = False   
 
    def update_bar(self, to_add_number): 
        while True: 
            time.sleep(0.01) 
            value = self.value() + to_add_number             
            self.setValue(value) 
            QtGui.qApp.processEvents() 
            if (not self._active or value >= self.maximum()):                 
                break 
        self._active = False 
 
    def closeEvent(self, event): 
        self._active = False 
 
def externalFunc(arg=None): 
    print "Attempting to update Progress Bar " 
    jobDialog.pb.update_bar(10) 
    print "...Completed." 
 
class MainWindow(QtGui.QMainWindow): 
    def __init__(self): 
        super(MainWindow, self).__init__() 
        self.main_layout = QtGui.QVBoxLayout() 
 
        self.pb=PbWidget(total=101) 
        self.main_layout.addWidget(self.pb) 
 
        ok_button = QtGui.QPushButton("OK") 
        ok_button.clicked.connect(self.OK) 
        self.main_layout.addWidget(ok_button)        
 
        central_widget = QtGui.QWidget() 
        central_widget.setLayout(self.main_layout) 
        self.setCentralWidget(central_widget) 
 
    def OK(self): 
        # externalFunc() 
        myList=[1,2,3] 
        from multiprocessing import Pool 
        pool = Pool(processes=10) 
        pool.map_async( externalFunc, myList) 
 
if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
 
    jobDialog = MainWindow() 
    jobDialog.resize(480, 320) 
    jobDialog.show() 
    sys.exit(app.exec_()) 

请您参考如下方法:

这是对我有用的解决方案的描述。

multiprocessing 的 Pool 方法(例如 ma​​p_async())启动的子进程无法与主进程中声明的变量(对象)通信(所有子流程都从中产生的流程)。如果我们只想发送任务进行处理就足够了。但我们通常需要来自子流程的“实时”反馈(当它们仍在处理收到的任务时)。为了在主流程及其所有子流程中为子流程提供变量“可见”(“共享”),我们使用 multiprocessing Manager()。语法非常简单:

from multiprocessing import Manager 
manager = Manager() 

在声明了一个 Manager() 实例后(这里称为 manager),我们继续声明一个变量……到目前为止,我知道 aka-dict 和 aka-list 类型。使用以下语法:

myDict=manager.dict() 

除了存储和检索数据外,这些变量还可用于设置/读取/重置用于启动/停止 while 循环函数(某种事件监听器)的 True/False 标志。这个想法是我们在后台运行一个 while 循环,它不断地监听(监视)这种 True 或 False 变量的状态。 这是修改后的代码,其中进度条由 multiprocessing Pool() map_async() 方法启动的子进程更新。

from PyQt4 import QtCore, QtGui 
 
from multiprocessing import Process, Manager, Pool 
manager = Manager() 
myDict=manager.dict() 
myDict['state'] = True 
myDict['value'] = 0 
 
 
class PbWidget(QtGui.QProgressBar): 
    def __init__(self, parent=None, total=20): 
        super(PbWidget, self).__init__() 
        self.setMinimum(1) 
        self.setMaximum(total)         
        self._active = False   
 
    def update_bar(self, to_add_number): 
        while True: 
            time.sleep(0.01) 
            value = self.value() + to_add_number             
            self.setValue(value) 
            QtGui.qApp.processEvents() 
            if (not self._active or value >= self.maximum()):                 
                break 
        self._active = False 
 
    def closeEvent(self, event): 
        self._active = False 
 
 
 
 
def externalFunc(arg=None): 
    print "\t\t Attempting to update Progress Bar by changing dictionary values" 
    myDict['value']=arg 
    myDict['state']=True 
 
class MainWindow(QtGui.QMainWindow): 
    def __init__(self): 
        super(MainWindow, self).__init__() 
        self.progressBarCurrentValue=0 
        self.main_layout = QtGui.QVBoxLayout() 
 
        self.pb=PbWidget(total=101) 
        self.main_layout.addWidget(self.pb) 
 
        ok_button = QtGui.QPushButton("OK") 
        ok_button.clicked.connect(self.OK) 
        self.main_layout.addWidget(ok_button)        
 
        central_widget = QtGui.QWidget() 
        central_widget.setLayout(self.main_layout) 
        self.setCentralWidget(central_widget) 
 
 
    def OK(self): 
        myList=[10,10,10,10,10,10,10,10,10,10,10,10,10] 
        pool = Pool(processes=10) 
        pool.map_async( externalFunc, myList) 
 
    def EventListener(self): 
        while myDict['state']:               
            value=myDict['value'] 
            self.pb.update_bar(value) 
 
            self.progressBarCurrentValue=self.pb.value() 
            print "...running sicne current Progress Bar value is < 99:", self.progressBarCurrentValue, myDict['state'] 
 
            if self.progressBarCurrentValue>99:  
                myDict['state'] = False 
                print "...stopping" 
 
 
 
if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv)     
    jobDialog = MainWindow() 
    jobDialog.resize(480, 320) 
    jobDialog.show() 
    jobDialog.EventListener() 
    sys.exit(app.exec_())