Подтвердить что ты не робот

Отправка пользовательских сигналов PyQt?

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

  • Основной/графический поток.

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

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

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

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

  • Как мне получить их в потоке Main/GUI?

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

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

Update:

Это выдержка из кода, который не работает. Во-первых, я пытаюсь "подключить" сигнал ( "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.

4b9b3361

Ответ 1

В этом примере:

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

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

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

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

Edit

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

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

Ответ 2

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

# 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)

Ответ 3

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

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

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

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

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

Update:

Вы получаете сообщение QObject::connect: Cannot queue arguments of type 'statuses', потому что вам нужно определить тип аргумента, который вы передадите, когда вы испустите свой сигнал. Тип, который вы хотите передать, list not 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 статически определяются как часть класса С++. Они есть с использованием QtCore.SIGNAL(). Эта метод принимает один строковый аргумент это имя сигнала и его С++. Например:

QtCore.SIGNAL("finished(int)")

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

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

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

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

QtCore.SIGNAL("finished(PyQt_PyObject)")

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

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

Ответ 4

Когда вы используете эти старые сигналы/слоты в 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)

Ответ 5

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

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

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