2016-03-01 1 views
2

Я внедрил версию рабочего шаблона, описанную в Qt Threading docs.Как отправить None с сигналами через потоки?

Я использую Signals/Slots для отправки данных между рабочей нитью и основным потоком.

При определении Signal я установил тип сигнатуры аргумента object, так как я считаю, что он должен позволить мне передать любой объект python через Signal.

result_ready = QtCore.Signal(object) 

Однако, когда я пытаюсь передать None через Signal он выходит из строя питона. Это происходит только при попытке передать Signal по потокам. Если я прокомментирую линию self.worker.moveToThread(self.thread), она работает, и None успешно проходит через Signal.

Почему я не могу пройти None в этом случае?

Я использую PySide 1.2.2 и Qt 4.8.5.

import sys 

from PySide import QtCore, QtGui 


class Worker(QtCore.QObject): 

    result_ready = QtCore.Signal(object) 

    @QtCore.Slot() 
    def work(self): 
     print 'In Worker' 

     # This works 
     self.result_ready.emit('Value') 

     # This causes python to crash 
     self.result_ready.emit(None) 


class Main(QtGui.QWidget): 

    def __init__(self): 
     super(Main, self).__init__() 
     self.ui_lay = QtGui.QVBoxLayout() 
     self.setLayout(self.ui_lay) 
     self.ui_btn = QtGui.QPushButton('Test', self) 
     self.ui_lay.addWidget(self.ui_btn) 
     self.ui_lay.addStretch() 
     self.setGeometry(400, 400, 400, 400) 
     self.worker = Worker() 
     self.thread = QtCore.QThread(self) 
     self.worker.moveToThread(self.thread) 
     self.thread.start() 
     self.ui_btn.clicked.connect(self.worker.work) 
     self.worker.result_ready.connect(self.handle_worker_result) 

    @QtCore.Slot(object) 
    def handle_worker_result(self, result=None): 
     print 'Handling output', result 

    def closeEvent(self, event): 
     self.thread.quit() 
     self.thread.wait() 
     super(Main, self).closeEvent(event) 


if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    obj = Main() 
    obj.show() 
    app.exec_() 

ответ

2

Это выглядит как PySide ошибка. Тот же пример кода работает точно так же, как и ожидалось с PyQt4.

Вопрос относится к type of signal connection. Для сигналов с поперечной резьбой это будет использовать QueuedConnection, если вы не укажете иное. Если тип соединения изменен на DirectConnection в примере кода, он будет работать так, как ожидалось, но, конечно, он больше не будет потокобезопасным.

A QueuedConnection отправит событие в очередь событий принимающей нити. Но для того, чтобы это было потокобезопасным, Qt должен сериализовать испущенные аргументы. Тем не менее, PySide, очевидно, нужно будет ввести какую-то магию здесь, чтобы иметь дело с типами python, о которых Qt ничего не знает. Если бы я должен был догадаться, я бы поспорил, что PySide ошибочно преобразует объект python None в указатель NULL C++, который, очевидно, будет иметь неприятные последствия позже.

Если вы хотите обойти это, я полагаю, вы могли бы испустить свой собственный объект дозорного в качестве заполнителя для None.

UPDATE:

Нашли ошибку, PYSIDE-17, которая была опубликована в марте 2012 года! К сожалению, предлагаемый патч, кажется, никогда не рассматривался.

1

Если вы меняете сигнал на соответствующий класс, тогда он отлично подходит для меня. например:

result_ready = QtCore.Signal(str) 

Это работает в обоих случаях.

Согласно документации

Сигналы могут быть определены с помощью класса QtCore.Signal(). Типы Python и типы C могут передаваться в качестве параметров. Если вам нужно перегрузить его, просто передайте типы как кортежи или списки.

https://wiki.qt.io/Signals_and_Slots_in_PySide#Using_QtCore.Signal.28.29

+0

Да, но это не сработает, если вы используете тип объекта, который фактически пытается испустить OP (т. Е. 'Type (None)'). – ekhumoro

+0

Согласитесь .. это было всего лишь обходным решением – Achayan

 Смежные вопросы

  • Нет связанных вопросов^_^