Найти - Пользователи
Полная версия: обновление ui в многопоточном приложении вызывает ошибки
Начало » GUI » обновление ui в многопоточном приложении вызывает ошибки
1
Игнат
Здравствуйте

есть программа для проверки прокси на валидность
python 3.2, pyqt4

по нажатию кнопки Старт запускается метод класса главного окна, который создает многопоточность:

        self.executor = ThreadPoolExecutor(max_workers=100) # 100 потоков
self.pending = set() # очередь

# можно ли сразу поместить сюда список прокси?
#self.future = self.executor.submit(self.worker, proxies)

# добавляем прокси в экзекутор
for proxy in proxies:
future = self.executor.submit(self.worker, proxy)
future.add_done_callback(self.process_result) # функция для обработки результата и обновления гуи
self.pending.add(future)
код self.worker самый простой:
    def worker(self, proxy):
# проверяем прокси, если всё ок возвращаем [1, proxy] либо [0, proxy]
и проблемная функция self.process_result:
    def process_result(self, future):

self.pending.discard(future)

if future.cancelled():
return

res, proxy = future.result()
print(res, proxy)

# increment progress bar
self.progress()

if res == 1:

self.textEdit('proxy_valid', 'add', proxy) # добавляем прокси в textEdit (это просто сокращение для self.ui.textEdit_proxy.appendPlainText(proxy))
# increment counter valid
self.lbl('valid')

elif res == 3:
pass
#self.log('bad format')
elif res == 4:
pass
#self.log('proxy down')
else:
self.lbl('invalid')
#self.log('no text')

#remove from 1st field
self.textEdit('proxy', 'del', proxy)

#decrement total
self.lbl('total', '-')

self.app.processEvents() # обновляем гуи, чтобы не зависал
self.app - это ссылка на app, который создается в самом начале скрипта:
    app = QtGui.QApplication(sys.argv)
form = run(app)
form.show()
sys.exit(app.exec_())
и собственно, проблема.
счётчики обновляются нормально, однако при попытке что-либо дописывать в textEdit'ы - в консоль валятся ошибки:
X Error: RenderBadGlyphSet (invalid GlyphSet parameter) 161
Extension: 148 (RENDER)
Minor opcode: 25 (RenderCompositeGlyphs32)
Resource id: 0x26

и

QWidget::repaint: Recursive repaint detected
ГУИ обновляется и с этими ошибками, но в итоге софт вылетает.

самое главное что я хочу узнать - можно ли напрямую обновлять self.ui из метода def process_result(self, future) ?
или это должно делаться иначе и все глюки от параллельного обращения к этому методу (и соотв. к уи) разных потоков?
Игнат
удалось!
очень помогло - http://www.saltycrane.com/blog/2008/01/pyqt-how-to-pass-arguments-while/

сначала создал 2 новых сигнала:
        self.connect(self, QtCore.SIGNAL("successSignal"),
self.update_success)

self.connect(self, QtCore.SIGNAL("failSignal"),
self.update_fail)
а в process_result вызвал их через emit

        if res == 1:
self.emit(QtCore.SIGNAL("successSignal"), proxy)
else:
self.emit(QtCore.SIGNAL("failSignal"), proxy)
при этом важно чтобы главный класс был унаследован от QtCore.QObject
иначе придется вызывать не через self:

QtCore.QObject.emit(QtCore.SIGNAL("failSignal"), proxy)
ну и 2 метода:
    def update_success(self, proxy):
self.lbl('valid')
self.textEdit('proxy_valid', 'add', proxy)
print(proxy, ' +')

def update_fail(self, proxy):
self.lbl('invalid')
print(proxy, ' -'
возможно кому-то это решение поможет, как помогло бы мне, найди я её раньше)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB