Envoyer des signaux PyQt personnalisés?

je pratique PyQt et (Q)threads en faisant un simple client Twitter. J'ai deux Qthreads.

  1. Principal/thread GUI.

  2. Twitter fetch thread récupère des données à partir de Twitter toutes les X minutes.

ainsi, toutes les X minutes, mon fil Twitter télécharge un nouvel ensemble de mises à jour d'état (une liste Python). Je veux passer cette liste au fil principal/GUI, donc qu'il peut mettre à jour la fenêtre avec ces statuts.

je suppose que je devrais utiliser le système signal / slot pour transférer les" Statuts " de la liste Python du fil Twitter, au fil principal/GUI. Ainsi, ma question Est double:

  1. Comment envoyer les statuts à partir du fil Twitter?

  2. comment les recevoir dans le fil Main/GUI?

autant que je puisse dire, PyQt ne peut par défaut envoyer des objets PyQt que via des signaux / slots. Je pense que je suis censé enregistrer un signal personnalisé que je peux ensuite envoyer, mais la documentation sur ce que j'ai trouvé n'est pas très claire pour un débutant comme moi. J'ai commandé un livre PyQt, mais il n'arrivera pas dans une semaine, et je ne veux pas attendre. :- )

j'utilise PyQt 4.6-1 sur Ubuntu

mise à Jour:

ceci est un excert du code qui ne fonctionne pas. Tout d'abord, j'essaie de connecter le signal ("newStatuses", un nom que je viens de faire) à la fonction auto.update_tweet_list dans la Main/thread GUI:

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

alors, dans le fil Twitter, je fais ceci:

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

quand cette ligne est appelée, je reçois le message suivant:

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

j'ai fait une recherche pour qRegisterMetaType () mais je n'ai pas trouvé tout ce qui concerne Python que je pourrais comprendre.

27
demandé sur Enfors 2010-04-06 18:14:20

5 réponses

de cet exemple:

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

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

vous pouvez écrire en Python

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

Modifier

La réponse extraite du commentaire:

self.emit(SIGNAL("newStatuses(PyQt_PyObject)"), statuses)
7
répondu Xavier 2015-04-17 08:12:28

vous pouvez aussi faire ceci, qui est beaucoup plus pythonique (et lisible!).

# 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)
25
répondu Mark Visser 2010-04-07 20:15:58

Cochez cette case question que j'ai posée il y a quelque temps. Il y a un exemple de code qui pourrait vous aider à comprendre ce que vous devez faire.

ce que vous avez dit à propos de l'enregistrement de votre signal me fait penser à ce code (tiré de la question susmentionnée):

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

je passe des cordes dans mon exemple, mais vous devriez pouvoir remplacer str par list .

s'il S'avère que vous ne pouvez pas passer des objets mutables, vous pouvez gérer vos résultats comme je le fais dans mon exemple (i.e. définir une variable results dans le thread, dire au thread principal qu'ils sont prêts, et avoir le thread principal "les ramasser").

mise à jour:

vous obtenez le message QObject::connect: Cannot queue arguments of type 'statuses' parce que vous avez besoin de définir le type de l'argument que vous passerez lorsque vous émettrez votre signal. Le type que vous voulez passer est list pas statuses .

quand vous connectez votre signal, il doit ressembler à ceci:

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

quand vous émettez votre signal, il doit ressembler à ceci:

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

étant donné que statuses est une liste. Notez que vous pouvez émettre une copie de votre liste en fonction de votre situation.

mise à Jour 2:

Ok, en utilisant list comme le type n'est pas correct. De L'aide de PyQt4 référence:

signaux PyQt et signaux Qt

les signaux Qt sont définis statiquement comme suit: partie d'une classe C++. Ils sont référencé à l'aide de la QtCore.SIGNAL() de la fonction. Ce la méthode prend un seul argument string c'est le nom du signal et de ses C++ signature. Par exemple::

QtCore.SIGNAL("finished(int)")

La valeur retournée est normalement passer au QtCore.QObject.connect() méthode.

PyQt permet de définir de nouveaux signaux dynamiquement. La loi d'émettre un Le signal PyQt le définit implicitement. Les signaux v4 de PyQt sont également référencés en utilisant le QtCore.SIGNAL() fonction.

Le PyQt_PyObject Signal D'Argument De Type

il est possible de passer n'importe quel Python objet comme argument de signal par en spécifiant PyQt_PyObject comme le type de l'argument signature. Par exemple::

QtCore.SIGNAL("finished(PyQt_PyObject)")

alors que cela serait normalement utilisé pour passant des objets comme des listes et dictionnaires comme arguments de signal, il peut être utilisé pour N'importe quel type de Python. Son avantage en passant, par exemple, un entier est que la normale conversions d'un objet Python à un C++ integer et back again ne sont pas requis.

le comptage de référence de l'objet être adopté est maintenu automatiquement. Il n'est pas nécessaire pour l'émetteur d'un signal de garder un référence à l'objet après l'appel QtCore.QObject.emit() , même si une connexion est en attente.

7
répondu tgray 2017-05-23 12:26:04

quand vous utilisez ces anciens signaux/fentes dans PyQt, il n'y a en fait pas besoin de déclarer des types du tout. Ceux-ci devraient fonctionner:

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

...

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

dans ce cas, PyQt va juste créer un nouveau type de signal pour vous à la volée lorsque vous émettez le signal. Si vous vouliez utiliser les signaux du nouveau style, alors il ressemblerait plus à:

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

....

self.newStatuses.emit(statuses)
6
répondu Luke 2011-03-03 21:31:49

(Py)Qt signaux et les slots de travail inter-threads tout de même que dans un seul thread. Il n'y a donc rien de vraiment spécial à mettre en place:

définit une fente (méthode) dans le filetage principal, et connecte le signal du filetage à cette fente (la connexion doit également se faire dans le filetage principal). Ensuite, dans le fil, quand vous voulez, juste émettre le signal et cela devrait fonctionner. voici un tutoriel sur l'utilisation des signaux et des fentes avec filetage dans PyQt.

je vous recommande de l'essayer sur un petit jouet premier exemple, avant de passer à votre demande.

3
répondu Eli Bendersky 2010-04-06 14:28:06