PyQt : signaux personnalisés, JPEG, survol de la souris et d'autres choses

Harsh

Traducteur

Thibaut Cuvelier

Voici des réponses aux questions les plus fréquemment recherchées sur mon blog.

Commentez

- Titre : PyQt : signaux personnalisés, JPEG, survol de la souris et d'autres choses

- Auteur : Harsh

- Traducteur : Thibaut Cuvelier

- Parution : 2 juin 2011

- Mise à jour : 2 février 2020

- Licence : Copyright ® 2010 Harsh. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Écrire des signaux personnalisés

- II. Sauvegarder une image en JPEG avec QImage

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

- IV. Bonus

- IV-A. Taille de l'écran

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

- V. Remerciements

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 :

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,

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.

# -*- 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ètres : 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 à leur slot
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 :

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 :

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.jpg")

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

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.

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 :

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() :

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 :

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 !