Я практикую PyQt и (Q) потоки путем создания простого клиента Твиттера. У меня есть два Qthreads.
Основной поток / поток GUI.
Поток выборки Твиттера - выбирает данные из Твиттера каждые X минуты.
Так, каждые X минуты мой поток Твиттера загружает новый набор обновлений статуса (список Python). Я хочу передать этот список Основному потоку / потоку GUI, так, чтобы он мог обновить окно с этими состояниями.
Я предполагаю, что должен использовать сигнал / система слота для передачи "состояний" список Python от потока Твиттера к Основному потоку / потоку GUI. Так, мой вопрос является двукратным:
Как я отправляю состояния от потока Твиттера?
Как я получаю их в Основном потоке / потоке GUI?
Насколько я могу сказать, PyQt может по умолчанию только отправить PyQt-объекты через сигналы / слоты. Я думаю, что я, как предполагается, так или иначе регистрирую пользовательский сигнал, который я могу затем отправить, но документация относительно этого, что я нашел, очень неясна новичку как я. Я сделал, чтобы PyQt заказал на порядке, но он не прибудет на другой неделе, и я не хочу ожидать до тех пор.:-)
Я использую PyQt 4.6-1 на Ubuntu
Обновление:
Это - проявление из кода, который не работает. Во-первых, я пытаюсь "соединить" сигнал ("newStatuses", имя, которое я просто составил) к функции сам update_tweet_list в Основном потоке / потоке GUI:
QtCore.QObject.connect(self.twit_in,
QtCore.SIGNAL("newStatuses (statuses)"),
self.update_tweet_list)
Затем в потоке Твиттера я делаю это:
self.emit(SIGNAL("newStatuses (statuses)"), statuses)
Когда эту строку называют, я получаю следующее сообщение:
QObject::connect: Cannot queue arguments of type 'statuses'
(Make sure 'statuses' is registered using qRegisterMetaType().)
Я сделал поиск qRegisterMetaType (), но я не нашел ничего касающегося Python, который я мог понять.
Из этого примера:
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)
Посмотрите этот вопрос, который я задал некоторое время назад. Вот пример кода, который может помочь вам понять, что вам нужно делать.
То, что вы сказали о регистрации вашего сигнала, заставляет меня думать об этом коде (из вышеупомянутого вопроса):
class ProcessingThread(threading.Thread, QtCore.QObject):
__pyqtSignals__ = ( "progressUpdated(str)",
"resultsReady(str)")
Я передаю строки в своем примере, но вы сможете заменить str
на список
.
Если выяснится, что вы не можете передавать изменяемые объекты, вы можете обработать свои результаты так, как я это делаю в моем примере (т.е. установить переменную results
в потоке, сообщить основному потоку, что они готовы, и пусть основной поток их «подхватит»).
Обновление:
Вы получаете сообщение QObject :: connect: Невозможно поставить в очередь аргументы типа 'статусы'
, потому что вам нужно определить тип аргумента, который вы передадите когда вы излучаете свой сигнал. Тип, который вы хотите передать, - это список
, а не статусы
.
Когда вы подключаете свой сигнал, он должен выглядеть так:
QtCore.QObject.connect(self.twit_in,
QtCore.SIGNAL("newStatuses(list)"),
self.update_tweet_list)
Когда вы излучаете свой сигнал, он должен выглядеть так:
self.emit(SIGNAL("newStatuses(list)"), statuses)
учитывая, что статусы
- это список. Обратите внимание, что вы можете захотеть создать полную копию своего списка в зависимости от вашей ситуации.
Обновление 2:
Хорошо, используется список
, поскольку тип неверен. Из справки по PyQt4:
Сигналы PyQt и сигналы Qt
Сигналы Qt статически определены как часть класса C ++. На них ссылаются с помощью функции
QtCore.SIGNAL ()
. Этот метод принимает единственный строковый аргумент , который представляет собой имя сигнала и его сигнатуру C ++. Например ::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 в целое число C ++ и обратно не являются {{ 1}} требуется.
Счетчик ссылок переданного объекта поддерживается автоматически. Нет необходимости, чтобы передатчик сигнала сохранял ссылку на объект после вызова
QtCore.QObject.emit ()
, даже если соединение поставлено в очередь.
(Py) Сигналы и слоты Qt работают между потоками точно так же, как и в одном потоке. Так что особо нечего настраивать:
Определите слот (метод) в основном потоке и подключите сигнал потока к этому слоту (соединение также должно быть выполнено в основном потоке). Затем в потоке, когда вы хотите, просто испустите сигнал, и он должен работать. Вот руководство по использованию сигналов и слотов с потоковой передачей в PyQt.
Я рекомендую вам сначала попробовать его на небольшом игрушечном примере, прежде чем переходить к вашему приложению.
Вы также можете сделать это, что гораздо более питонично (и читается!).
# 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)