View  Edit  Attributes  History  Attach  Print  Search

PYQTLAB

PyQt Lab' : Dessiner un carré, une ligne, un cercle..

Par X. HINAULT - Juin 2013

Ce que l'on va faire ici

  • Dans ce code PyQt, je vous propose de voir comment afficher des formes simples dans une image affichée dans un QLabel.
  • Le principe ici consiste :
    • à créer un QImage
    • à créer un QPainter associé au QImage
    • à dessiner des formes sur le QImage en appelant les fonctions de dessin fournies par le QPainter, en paramétrant au préalable le QPen utilisé
    • à copier ensuite le QImage dans un QPixmap pour un affichage dans un QLabel
  • Noter que l'on pourrait dessiner directement sur le QPixmap.. en lui associant le QPainter (au lieu du QImage). Mais l'utilisation d'un QPixmap présente plusieurs avantages potentiels : servir de "buffer" de travail avant affichage, permet l'accès au pixels unitaires au besoin, permet d'utiliser un tableau numpy pour la définition de l'image si besoin, etc...)

Pré-requis

  • python 2.7
  • pyqt4.x

Le fichier d'interface *.py

  • Fichier obtenu automatiquement avec l'utilitaire pyuic4 à partir du fichier *.ui créé avec QtDesigner :

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file
#
# Created: Wed Jun 12 11:27:52 2013
#      by: PyQt4 UI code generator 4.9.1
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName(_fromUtf8("Form"))
        Form.resize(333, 267)
        self.labelImage = QtGui.QLabel(Form)
        self.labelImage.setGeometry(QtCore.QRect(5, 15, 320, 240))
        self.labelImage.setStyleSheet(_fromUtf8("background-color: rgb(180, 180, 180);"))
        self.labelImage.setText(_fromUtf8(""))
        self.labelImage.setObjectName(_fromUtf8("labelImage"))

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        Form.setWindowTitle(QtGui.QApplication.translate("Form", "PyQt : dessin : qpixmap et formes", None, QtGui.QApplication.UnicodeUTF8))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    Form = QtGui.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())
 

Le fichier d'application *Main.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

# par X. HINAULT - Mai 2013 - Tous droits réservés
# GPLv3 - www.mon-club-elec.fr

# modules a importer
from PyQt4.QtGui import *
from PyQt4.QtCore import *  # inclut QTimer..
import os,sys

from tuto_pyqt_dessin_qpixmap_formes import * # fichier obtenu à partir QtDesigner et pyuic4

# +/- variables et objets globaux

class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4
        def __init__(self, parent=None):
                QWidget.__init__(self) # initialise le Qwidget principal
                self.setupUi(parent) # Obligatoire

                # --- Variables de classe

                # --- Paramétrage des widgets de l'interface GUI si nécessaire ---

                # --- Connexions entre signaux des widgets et fonctions
                # connecte chaque signal utilisé des objets à l'appel de la fonction voulue

                # --- Code actif initial  ---


                # Dessin avec QPixmap (affichage) et QImage (I/O, accès pixels)

                # création d'un QImage permettant l'accès aux pixels
                self.image=QImage(self.labelImage.size(),QImage.Format_RGB32) # crée image RGB 32 bits même taille que label

                #-- opérations de dessin sur le QImage
                self.image.fill(QColor(255,255,255)) # fond blanc

                # coordonnées centre du QPixmap (même taille que label)
                xo=self.image.width()/2
                yo=self.image.height()/2

                #trace le point
                #self.image.setPixel(xo,yo,qRgb(0,0,0)) # modifie la couleur du pixel x,y - noter qRgb renvoie valeur RGB 0xFFRRGGBB

                #--- dessin de formes --
                self.painter=QPainter(self.image) # associe QPainter (classe de dessin) au Qimage

                # paramètres crayon dessin
                #self.painter.setPen(QPen(Qt.SolidLine)) # fixe la couleur du crayon pour le dessin - moins propre...
                self.pen=QPen(Qt.SolidLine) # crayon par défaut pour le painter - ligne continue
                self.pen.setWidth(3) # fixe largeur crayon
                self.pen.setColor(QColor(0,0,255)) # fixe couleur crayon               
                self.painter.setPen(self.pen) # affecte le crayon defini au dessin - les paramètres s'appliquent seulement une fois setPen() appelé

                # tracé point simple
                self.painter.drawPoint(xo,yo) # trace un point drawPoint (self, int x, int y)

                # tracé rectangle vide
                self.painter.drawRect(10,10,50,50) # dessin rectangle : drawRect (self, int x, int y, int w, int h)

                # tracé rectangle plein
                self.painter.fillRect(150,150,30,30,QColor(255,255,0)) # fillRect (self, int x, int y, int w, int h, QColor b)

                # tracé cercle
                self.painter.setPen(QColor(255,0,0)) # fixe la couleur du crayon pour le dessin - width=1 par défaut
                self.painter.drawEllipse(xo,yo,50,50) # dessin cercle - x-y = coin sup gauche rect encadrant : drawEllipse (self, int x, int y, int w, int h)

                self.painter.setPen(QPen(QColor(255,64,255),5)) # fixe la couleur du crayon et la largeur pour le dessin - forme compactée
                # cf QPen(QBrush brush, float width, Qt.PenStyle style = Qt.SolidLine, Qt.PenCapStyle cap = Qt.SquareCap, Qt.PenJoinStyle join = Qt.BevelJoin)
                self.painter.drawEllipse(QPointF(xo,yo),50,50) # dessin cercle avec x,y centre et rayon : drawEllipse (self, QPointF center, float rx, float ry)

                # tracé ligne
                self.painter.setPen(QPen(QColor(40,255,127),2)) # fixe la couleur du crayon et la largeur pour le dessin - forme compactée
                self.painter.drawLine(0,0,xo*2,yo) # trace une ligne : drawLine (self, int x1, int y1, int x2, int y2)

                # tracé texte
                self.painter.setPen(QPen(QColor(0,0,255),2)) # fixe la couleur du crayon et la largeur pour le dessin - forme compactée        
                self.painter.drawText(QPointF(xo/2, yo/2), "Hello") # drawText (self, QPointF p, QString s)

                # il existe d'autres possibilités de dessin (polygone, chemin, etc..) voir : http://pyqt.sourceforge.net/Docs/PyQt4/qpainter.html

                self.painter.end() # ferme le painter - n'est plus accessible après

                # -- fin dessin de formes

                #-- affichage du QImage via QPixmap dans QLabel
                self.pixmap=QPixmap.fromImage(self.image) # chargement qu QImage dans le QPixmap - fonction begin intégrée...
                self.labelImage.setPixmap(self.pixmap) # met à jour le qpixmap affiché dans le qlabel


        # --- les fonctions appelées, utilisées par les signaux des widgets ---

        # --- les fonctions appelées, utilisées par les signaux hors widgets ---

        # --- fonctions de classes autres---    

# -- Autres Classes utiles --

# -- Classe principale (lancement)  --
def main(args):
        a=QApplication(args) # crée l'objet application
        f=QWidget() # crée le QWidget racine
        c=myApp(f) # appelle la classe contenant le code de l'application
        f.show() # affiche la fenêtre QWidget
        r=a.exec_() # lance l'exécution de l'application
        return r

if __name__=="__main__": # pour rendre le code exécutable
        main(sys.argv) # appelle la fonction main
 

Utilisation

  • Les 2 fichiers suivants sont à enregistrer dans un même répertoire, l'un en nom.py et l'autre en nomMain.py.
  • Puis lancer l'application depuis Geany ou équivalent, en exécutant le fichier nomMain.py
  • Le dessin doit s'afficher au lancement.