Отправка пользовательских сигналов PyQt? - PullRequest
27 голосов
/ 06 апреля 2010

Я практикую потоки PyQt и (Q), делая простой клиент Twitter.У меня есть два Qthreads.

  1. Основная / GUI-нить.

  2. Twitter fetch thread - извлекает данные из Twitter каждые X минут.

Итак, каждые X минут мой поток в Твиттере загружает новый набор обновлений статуса (список Python).Я хочу передать этот список потоку Main / GUI, чтобы он мог обновить окно с этими статусами.

Я предполагаю, что я должен использовать систему сигналов / слотов для передачи "статусов"Msgstr "Список Python из ветки Twitter, в ветку Main / GUI.Итак, мой вопрос состоит из двух частей:

  1. Как отправить статусы из ветки Twitter?

  2. Как я могу получить их на главнойПоток / GUI?

Насколько я могу судить, PyQt может по умолчанию отправлять PyQt-объекты только через сигналы / слоты.Я думаю, что я должен каким-то образом зарегистрировать пользовательский сигнал, который я могу затем отправить, но документация по этому вопросу, которую я нашел, очень неясна для новичка, как я.У меня есть книга PyQt по заказу, но она не появится через неделю, и я не хочу ждать до тех пор.: -)

Я использую PyQt 4.6-1 в Ubuntu

Обновление:

Это выдержка из кода, который неРабота.Сначала я пытаюсь «подключить» сигнал («newStatuses», имя, которое я только что придумал) к функции self.update_tweet_list в потоке Main / GUI:

QtCore.QObject.connect(self.twit_in,
                       QtCore.SIGNAL("newStatuses (statuses)"),
                       self.update_tweet_list)

Затем в потоке Twitter, Я делаю это:

self.emit(SIGNAL("newStatuses (statuses)"), statuses)

Когда эта строка вызывается, я получаю следующее сообщение:

QObject::connect: Cannot queue arguments of type 'statuses'
(Make sure 'statuses' is registered using qRegisterMetaType().)

Я выполнил поиск qRegisterMetaType (), но ничего не нашелкасательно Python, который я мог понять.

Ответы [ 5 ]

25 голосов
/ 08 апреля 2010

Вы также можете сделать это, что гораздо более питонно (и читабельно!).

# create a signal equivalent to "void someSignal(int, QWidget)"
someSignal = QtCore.pyqtSignal(int, QtGui.QWidget)

# define a slot with the same signature
@QtCore.pyqtSlot(int, QtGui.QWidget)
def someSlot(status, source):
    pass

# connect the signal to the slot
self.someSignal.connect(self.someSlot)
7 голосов
/ 06 апреля 2010

Проверьте этот вопрос, который я задал некоторое время назад. Существует пример кода, который может помочь вам понять, что вам нужно делать.

То, что вы сказали о регистрации вашего сигнала, заставляет меня подумать об этом коде (из вышеупомянутого вопроса):

class ProcessingThread(threading.Thread, QtCore.QObject):
    __pyqtSignals__ = ( "progressUpdated(str)",
                        "resultsReady(str)")

Я передаю строки в моем примере, но вы должны заменить str на list.

Если окажется, что вы не можете передать изменяемые объекты, вы можете обработать свои результаты так, как я делаю в моем примере (т.е. установить переменную results в потоке, сообщить основному потоку, что они готовы, и есть основная тема "забрать их").

Обновление:

Вы получаете сообщение QObject::connect: Cannot queue arguments of type 'statuses', потому что вам нужно определить тип аргумента, который вы передадите, когда будете излучать свой сигнал. Тип, который вы хотите передать - list, а не statuses.

Когда вы подключаете свой сигнал, он должен выглядеть так:

QtCore.QObject.connect(self.twit_in,
                       QtCore.SIGNAL("newStatuses(list)"),
                       self.update_tweet_list)

Когда вы излучаете сигнал, он должен выглядеть следующим образом:

self.emit(SIGNAL("newStatuses(list)"), statuses)

, учитывая, что statuses является списком. Обратите внимание, что вы можете создать копию вашего списка в зависимости от вашей ситуации.

Обновление 2:

Хорошо, использование list в качестве неверного типа. Из справки PyQt4:

Сигналы PyQt и сигналы Qt

Сигналы Qt статически определены как часть класса C ++. Они есть ссылается с помощью QtCore.SIGNAL() функция. это метод принимает один строковый аргумент это название сигнала и его С ++ подпись. Например ::

QtCore.SIGNAL("finished(int)")

возвращаемое значение обычно передается к QtCore.QObject.connect() Метод.

PyQt позволяет определять новые сигналы динамически. Акт испускания Сигнал PyQt неявно определяет его. На сигналы PyQt v4 также ссылаются используя QtCore.SIGNAL() функция.

Тип аргумента PyQt_PyObject

Можно пропустить любой Питон объект в качестве аргумента сигнала указав PyQt_PyObject в качестве Тип аргумента в подписи. Например ::

QtCore.SIGNAL("finished(PyQt_PyObject)")

Хотя обычно это используется для прохождение объектов, таких как списки и словари в качестве аргументов, это может быть использован для любого типа Python. это преимущество при прохождении, например, целое число является нормальным преобразования из объекта Python в C ++ целое число и обратно не являются требуется.

Количество ссылок объекта проходя поддерживается автоматически. Там нет необходимости излучатель сигнала, чтобы сохранить ссылка на объект после вызова до QtCore.QObject.emit(), даже если соединение ставится в очередь.

7 голосов
/ 06 апреля 2010

Из этого примера:

http://doc.qt.digia.com/4.5/qmetatype.html

 int id = QMetaType.type("MyClass");

Вы можете записать на Python

from PyQt4 import QtCore    
id = QtCore.QMetaType.type('MyClass')

Редактировать

Ответ извлечен из комментария:

self.emit(SIGNAL("newStatuses(PyQt_PyObject)"), statuses)
6 голосов
/ 04 марта 2011

Когда вы используете эти сигналы / слоты старого стиля в PyQt, вам вообще не нужно объявлять типы. Это должно работать:

QtCore.QObject.connect(self.twit_in,
                   QtCore.SIGNAL("newStatuses"),
                   self.update_tweet_list)

...

self.emit(SIGNAL("newStatuses"), statuses)

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

class TwitterThread(QThread):
    newStatuses = pyqtSignal(object)

....

self.newStatuses.emit(statuses)
3 голосов
/ 06 апреля 2010

(Py) Сигналы и слоты Qt работают в перекрестных потоках так же, как в одном потоке. Так что нет ничего особенного в настройке:

Определите слот (метод) в главном потоке и подключите сигнал потока к этому слоту (соединение также должно быть сделано в основном потоке). Затем, в потоке, когда вы хотите, просто испустите сигнал, и он должен работать. Вот учебник по использованию сигналов и слотов с многопоточностью в PyQt.

Я рекомендую вам сначала попробовать его на маленьком игрушечном примере, прежде чем переходить к вашему приложению.

...