El envío de señales personalizados PyQt?
Pregunta
Estoy practicando hilos (Q) PyQt y haciendo un simple cliente de Twitter. Tengo dos Qthreads.
-
principal / hilo GUI.
-
Twitter traiga hilo -. Datos recupera de Twitter cada X minutos
Por lo tanto, cada X minutos mi hilo Twitter descarga un nuevo conjunto de cambios de estado (una lista de Python). Quiero entregar esta lista a lo largo del hilo principal / interfaz gráfica de usuario, de modo que pueda actualizar la ventana con estos estados.
Estoy asumiendo que debo utilizar el sistema de señal / ranura para transferir los "estados" lista de Python desde el hilo de Twitter, al hilo principal / GUI. Por lo tanto, mi pregunta es doble:
-
¿Cómo se envían los estados de la rosca Twitter?
-
¿Cómo los recibo en el hilo principal / GUI?
Por lo que yo puedo decir, PyQt puede enviar por defecto sólo PyQt-objetos a través de señales / ranuras. Creo que se supone que de alguna manera registrar una señal personalizada que luego puedo enviar, pero la documentación sobre este que he encontrado es muy claro para un novato como yo. Tengo un libro PyQt en orden, pero no va a llegar dentro de una semana, y yo no quiero esperar hasta entonces. : -)
Estoy usando PyQt 4.6-1 en Ubuntu
Actualización:
Este es un excert a partir del código que no funciona. En primer lugar, trato de la señal ( "newStatuses", nombre acabo de componer) a la self.update_tweet_list función en el hilo principal / GUI "conectar":
QtCore.QObject.connect(self.twit_in,
QtCore.SIGNAL("newStatuses (statuses)"),
self.update_tweet_list)
A continuación, en el hilo de Twitter, hago esto:
self.emit(SIGNAL("newStatuses (statuses)"), statuses)
Cuando esta línea se llama, me sale el siguiente mensaje:
QObject::connect: Cannot queue arguments of type 'statuses'
(Make sure 'statuses' is registered using qRegisterMetaType().)
Hice una búsqueda para qRegisterMetaType (), pero no he encontrado nada relacionado con Python que pude entender.
Solución
A partir de este ejemplo:
http://doc.qt.digia.com/4.5/qmetatype.html
int id = QMetaType.type("MyClass");
Se puede escribir en Python
from PyQt4 import QtCore
id = QtCore.QMetaType.type('MyClass')
Editar
La respuesta extraído del comentario:
self.emit(SIGNAL("newStatuses(PyQt_PyObject)"), statuses)
Otros consejos
También puede hacer esto, que es mucho más Pythonic (y legible!).
# 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)
Consulte esta pregunta que hice un tiempo atrás. Hay un ejemplo de código que podrían ayudar a determinar lo que hay que hacer.
Lo que ha dicho sobre cómo registrar su señal me hace pensar en el código (de la pregunta antes mencionada):
class ProcessingThread(threading.Thread, QtCore.QObject):
__pyqtSignals__ = ( "progressUpdated(str)",
"resultsReady(str)")
Estoy de paso cuerdas en mi ejemplo, pero usted debería ser capaz de reemplazar con str
list
.
Si resulta que no se puede pasar objetos mutables, que puede manejar los resultados de la manera que lo hago en mi ejemplo (es decir, establecer una variable results
en el hilo, el hilo principal decir que están listos, y tienen la hilo principal "recogerlos").
Actualización:
Se obtiene el mensaje QObject::connect: Cannot queue arguments of type 'statuses'
porque es necesario para definir el type del argumento que va a pasar cuando se emiten su señal. El tipo que desea pasar es no list
statuses
.
Cuando se conecta la señal que debe tener este aspecto:
QtCore.QObject.connect(self.twit_in,
QtCore.SIGNAL("newStatuses(list)"),
self.update_tweet_list)
Cuando usted emite su señal que debe ser similar al siguiente:
self.emit(SIGNAL("newStatuses(list)"), statuses)
dado que statuses
es una lista. Tenga en cuenta que es posible que desee emitir una copia profunda de su lista en función de su situación.
Actualización 2:
Ok, usando list
como el tipo no es correcto. A partir de la referencia de ayuda PyQt4:
Señales PyQt y señales Qt
señales Qt se definen como estáticamente parte de la clase una C ++. Son referenciado usando el
QtCore.SIGNAL()
función. Esta método toma un único argumento de cadena que es el nombre de la señal y su C ++ firma. Por ejemplo ::QtCore.SIGNAL("finished(int)")
El valor devuelto se pasa normalmente a la
QtCore.QObject.connect()
método.PyQt permite nuevas señales a ser definidos dinamicamente. El acto de emitir una PyQt señal que define implícitamente. señales v4 PyQt también se hace referencia a usando el
QtCore.SIGNAL()
función.El
PyQt_PyObject
Tipo de señal ArgumentoEs posible pasar cualquier Python objeto como un argumento señal por especificando
PyQt_PyObject
como el tipo del argumento en la firma. Por ejemplo ::QtCore.SIGNAL("finished(PyQt_PyObject)")
Si bien esto normalmente sería utilizado para pasar objetos como listas y diccionarios como argumentos de señal, se puede ser utilizado para cualquier tipo Python. Sus ventaja cuando se pasa, por ejemplo, un número entero es que el normal de las conversiones de un objeto Python a una número entero C ++ y de nuevo no son requerido.
El recuento de referencia del objeto ser pasado se mantiene automáticamente. No hay ninguna necesidad de el emisor de una señal para mantener una referencia al objeto después de la llamada a
QtCore.QObject.emit()
, incluso si una conexión se pone en cola.
Al utilizar estas señales / ranuras de estilo antiguo en PyQt, hay en realidad no hay necesidad de declarar tipos en absoluto. Estos deben trabajar:
QtCore.QObject.connect(self.twit_in,
QtCore.SIGNAL("newStatuses"),
self.update_tweet_list)
...
self.emit(SIGNAL("newStatuses"), statuses)
En este caso, PyQt se acaba de crear un nuevo tipo de señal para que sobre la marcha cuando usted emite la señal. Si quería usuario las señales de nuevo estilo, a continuación, se vería más como:
class TwitterThread(QThread):
newStatuses = pyqtSignal(object)
....
self.newStatuses.emit(statuses)
señales y ranuras (Py) Qt trabajan transversales hilos de la misma manera como en un solo hilo. Así que no hay nada realmente especial de configurar:
definir una ranura (método) en el hilo principal, y conectar la señal del hilo a esta ranura (la conexión deberá ser también hecho en el hilo principal). Luego, en el hilo, cuando se desea, simplemente emitir la señal y debería funcionar. Aquí hay un tutorial sobre el uso de señales y slots con hilo en PyQt.
Te recomiendo probarlo en un pequeño ejemplo de juguete en primer lugar, antes de pasar a su aplicación.