I. Écrire des signaux personnalisés

Écrire des signaux personnalisés que l'on peut émettre à l'occasion de certains événements est une tâche facile. On doit d'abord créer l'objet de signal. Ceci se fait en utilisant la fonction pyqtSignal() de PyQt.QtCore. Voici sa signature :

 
Sélectionnez
QtCore.pyqtSignal([optional argument types], [optional name])

On doit créer un objet de signal en utilisant ce signal comme propriété de la classe, ensuite appeler sa méthode connect() pour finalement l'émettre. Sous forme de diagramme,

Image non disponible

Le code ci-dessous explique trois types de signal :

  • un signal sans argument - simpleSig ;
  • un signal avec quelques arguments - argumentSig ;
  • un signal avec des arguments de plusieurs types (surcharge) - doubleSig.
 
Sélectionnez
# -*- coding: utf-8 -*-
from PyQt4.QtGui import *
from PyQt4.QtCore import *
 
import sys
 
class MyWidget(QWidget):
    # Définition des signaux
 
    # Pas d'argument, un simple signal qui peut être émis
    simpleSig = pyqtSignal()
 
 	# Un signal qui requiert deux paramètre : un entier
 	# et une liste Python. On peut aussi en avoir plus 
 	# de deux. 
    argumentSig = pyqtSignal(int, list)
 
    # Un signal qui peut envoyer deux ensembles différents
    # de paramètres : l'un pour un int, l'autre pour une QString. 
    # Ce signal est aussi nommé name pour utilisation dans des 
    # buts plus dynamiques. 
    doubleSig = pyqtSignal((int,), (QString,), name='doubles')
 
    def __init__(self, parent=None):
    	# Construction du parent, à ne jamais oublier !
        super(MyWidget, self).__init__(parent)
 
        # On connecte les signaux à leurs slots
        self.simpleSig.connect(self.simpleSlot)
        self.argumentSig.connect(self.argumentSlot)
        # On a le même slot pour les signaux doubles (surchargés), 
        # parce que l'on peut aussi vérifier l'argument depuis
        # l'intérieur
        self.doubleSig['int'].connect(self.doubleSlot)
        self.doubleSig['QString'].connect(self.doubleSlot)
 
        # On connecte le bouton à un slot qui va appeler les signaux. 
        self.button = QPushButton('Press me', self)
        self.button.clicked.connect(self.buttonClicked)
 
    def buttonClicked(self, checked=False):
        # On émet les signaux pour les utiliser. 
        self.simpleSig.emit()
        self.argumentSig.emit(2, [1,2,3])
        # Les signaux surchargés ont le format suivant. 
        self.doubleSig['int'].emit(42)
        self.doubleSig['QString'].emit('Hitchhiking a ride.')
 
    # Définition des slots 
 
    def simpleSlot(self):
        # Sans argument
        print "Simple custom signal:",
        print "No arguments in this type of signal."
 
    def argumentSlot(self, *args):
        # (ou 'argumentSlot(self, intArg, listArg)')
        # Possède deux arguments, qui sont regroupés en un seul avec *
        print "Multi-argument signal:",
        print "Two arguments were passed: value: '%d' of %s and value: '%s' of %s." % (args[0], type(args[0]), args[1], type(args[1]))
 
    def doubleSlot(self, someArgument):
        # Ce slot gère doubleSig(int)
        # et doubleSig(QString)
        print "Overloaded signal:",
        print "An argument was passed and it was of '%s' and value: '%s'." % (type(someArgument), someArgument)
 
if __name__=='__main__':
    app = QApplication(sys.argv)
    widget = MyWidget()
    widget.show()
    app.exec_()

La sortie à l'exécution de cet exemple pourrait être :

 
Sélectionnez
Simple custom signal: No arguments in this type of signal.
Multi-argument signal: Two arguments were passed: value: '2' of <type 'int'> and value: '[1, 2, 3]' of <type 'list'>.
Overloaded signal: An argument was passed and it was of '<type 'int'>' and value: '42'
Overloaded signal: An argument was passed and it was of '<class 'PyQt4.QtCore.QString'>' and value: 'Hitchhiking a ride.'

Référence : la documentation de PyQt.

II. Sauvegarder une image en JPEG avec QImage

JPEG est un format d'image génial mais avec pertes. PyQt supporte le JPEG si un plug-in libjpeg est disponible sur le système. Peu importe, voici comment sauvegarder une QImage en JPEG :

 
Sélectionnez
img = QImage(50, 50, QImage.Format_RGB32)
painter = QPainter(img)
painter.setBrush(QBrush(QColor('#ff0000')))
painter.drawRect(0,0,50,50)
painter.end()
img.save("sample.jpeg")

Ce snippet crée une image sample.jpeg qui ressemble à ceci :

Image non disponible

Références : QImage et QPainter.

III. Suivre la souris de près avec les événements de survol

Les événements de survol (aussi connus sous le nom de mouseMoveEvent(event) du côté de PyQt) sont suivis par défaut si un bouton de la souris est pressé puis relâché. Cependant, si on veut aussi suivre les mouvements de la souris quand elle survole une zone sans qu'un bouton soit appuyé, on va devoir activer la propriété mouseTracking de QWidget. Ainsi, on doit appeler widget.setMouseTracking(true). Le snippet suivant est un simple programme qui affiche les coordonnées du pointeur de la souris tant qu'il survole la fenêtre.

 
Sélectionnez
from PyQt4.QtGui import *
from PyQt4.QtCore import *
 
import sys
 
class MyWidget(QWidget):
 
    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)
 
        self.setMouseTracking(True)
 
    def mouseMoveEvent(self, event):
        print "Mouse Pointer is currently hovering at: ", event.pos()
 
if __name__=='__main__':
    app = QApplication(sys.argv)
    widget = MyWidget()
    widget.show()
    app.exec_()

Il devrait ressortir quelque chose comme ceci :

 
Sélectionnez
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(415, 66)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(420, 60)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(424, 56)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(427, 51)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(433, 41)
Mouse Pointer is currently hovering at:  PyQt4.QtCore.QPoint(438, 36)

On peut aussi procéder en définissant un attribut Qt.Hover par QWidget.setAttribute(attribute) puis en filtrant ces événements.

Référence : QMouseEvent.

IV. Bonus

IV-A. Taille de l'écran

Pour récupérer la taille de l'écran (la résolution d'affichage, en d'autres mots), il suffit d'accéder au widget du bureau par QApplication.desktop(), une méthode statique, il n'est donc pas nécessaire d'avoir un objet QApplication. On peut alors en récupérer la size() :

 
Sélectionnez
QApplication.desktop().size()

Référence : QApplication.

IV-B. Définir la taille de la fenêtre

On peut définir la taille de la fenêtre comme celle de n'importe quel widget, on doit juste définir sa propriété de géométrie, peu importe la classe :

 
Sélectionnez
widgetObj.setGeometry(x, y, width, height)

Référence : QWidget.

V. Remerciements

Merci à Harsh pour l'autorisation de traduire son article, PyQt FAQ – Custom Signals, JPEG, Mouse Hovers and More !

Merci à Jean-Philippe André pour sa relecture orthographique !