Utiliser PyQt4 avec QtDesigner

Sommaire

La bibliothèque Qt4 et son équivalent Python PyQt4

Si jamais vous avez déjà programmé en Python avec la bibliothèque d'origine TkInter, vous savez déjà que coder une interface utilisateur à la main est une tâche à la fois longue et fastidieuse.

QtDesigner est l'outil fourni par la bibliothèque Qt qui vous permet de réaliser une GUI (en Français une IHM : Interface Homme-Machine), par le biais d'un système de glisser-déposer. Il est ainsi possible de créer trois types de « formes » : des widgets, des dialogues ou des applications, tout ceci vous étant demandé par QtDesigner lors de création d'une nouvelle « form » (à partir du menu, choisir File/New Form).

QtDesigner ne génère pas de code source directement. Il peut uniquement sauvegarder votre « forme » avec l'extension « .ui », un dérivé du format XML. Il vous est alors possible, grâce à un module nommé « uic » (lui même écrit en Python) de générer le code Python à l'interface que vous avez précédemment déssiné. C'est à la fois un gain de temps et de productivité, mais aussi une bonne façon de séparer le fond de la forme de votre interface.

C'est l'utilitaire en ligne de commande nommé « pyuic4 » qui vous permettra de manipuler le module « uic », il sera détaillé un peu plus loin.

Remarque : À l'origine le toolkit Qt, écrit en C++ dispose d'une classe QUiLoader qui permet à une application de charger un fichier « .ui » et de générer son code dynamiquement. PyQt n'englobe pas la classe QuiLoader, mais propose à la place

Dessiner notre interface

Ouvrez QtDesigner et créez une nouvelle forme de type « MainWindow », qui sera donc une application à part entière. Choisissez alors un « Push Button » dans la Widget Box et glissez-le dans votre interface. Sauvegardez celle-ci par File/Save Form As... et entrez « MonAppli », ce sera votre fichier « .ui » généré. Voici le mien:

<ui version="4.0" >
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>1</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle" >
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget" >
<widget class="QPushButton" name="pushButton" >
<property name="geometry" >
<rect>
<x>80</x>
<y>130</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text" >
<string>PushButton</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar" />
</widget>
<resources/>
<connections/>
</ui>

Ce n'est ni plus ni moins qu'un fichier XML, comme nous l'avions souligné dans l'introduction.

Transformer le fichier « .ui » en code Python:

Notre fichier « MonAppli.ui » ne sert pas à grand chose pour le moment, c'est un fait. Il va nous falloir le tranformer en code Python, grâce à l'utilitaire pyuic4.

Passez en ligne de commande, dans le répertoire ou vous avez sauvegarder votre fichier « MonAppli.ui », et entrez ceci:

>>pyuic4 -o MonAppli.py -x MonAppli.ui

La syntaxe générale de l'utilitaire puyic4 est la suivante:

>>pyuic4 [options] LeFichier.ui

Les options de pyuic4 sont répértoriées dans la tableau suivant:

Options Utilité
-h ou --help Un message d' aide apparait à la sortie
-version Le numéro de version est écrit sur la sortie.
i N ou --indent=N Le code source Python généré sera indenté de n espaces par défaut. Si N=0 des tabulations sont utilisées au lieu des espaces La valeur par défaut est N=4
-o Fichier ou --output=Fichier Le source est généré dans un fichier dont il faut donner l' extension ".py"
-p ou --preview L'interface est généréé dyna miquement, et aucun source Python n'est créé.
-x ou --execute Le code source généré compor tera un petit bout de code supplementaire pour être exé cutable.

Note: Pour les utilisateurs de Windows, je vous conseille d'installer le PowerToy « Open Command Window Here » disponible sur le site de MicroSoft, qui comme son nom l'indique vous permet d'ouvrir une ligne de commande là ou vous vous trouvez en cliquant droit sur un fichier système.

La ligne que nous venons de taper demande donc à puyic4 de créer un fichier « MonAppli.py » de type exécutable à partir du fichier original « MonAppli.ui ».

Voici le code source Python obtenu dans le fichier « MonAppli.py ».

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

# Form implementation generated from reading ui file 'unknown'
#
# Created: Sat Oct 21 14:57:01 2006
#      by: PyQt4 UI code generator 4.0
#
# WARNING! All changes made in this file will be lost!

import sys
from PyQt4 import QtCore, QtGui

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,800,600).size()).expandedTo(MainWindow.minimumSizeHint()))

        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(1),QtGui.QSizePolicy.Policy(1))
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
        MainWindow.setSizePolicy(sizePolicy)

        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        self.pushButton = QtGui.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(80,130,75,23))
        self.pushButton.setObjectName("pushButton")
        MainWindow.setCentralWidget(self.centralwidget)

        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0,0,800,21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)

        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def tr(self, string):
        return QtGui.QApplication.translate("MainWindow", string, None, QtGui.QApplication.UnicodeUTF8)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(self.tr("MainWindow"))
        self.pushButton.setText(self.tr("PushButton"))


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Note: L'option « -x » a simplement permis d'ajouter le petit bout de code qui commence par « if __name__ == "__main__": » et colorié ici en gris-bleu, bien connu des utilisateurs Python afin de rendre celui-ci exécutable.

Une autre façon de procéder:

Il nous est aussi possible d'utiliser directement le fichier « .ui », et ceci sans générer de code Python à partir de ce dernier.

Il existe pour cela plusieurs façons de faire et nous allons détailler chacune d'entre elles, et en dresser les avantages et inconvénients.

Apeller dynamiquement le fichier « .ui »:

Avec votre éditeur préféré, créez un nouveau fichier que nous nommerons « lanceur.py » et qui contiendra les lignes suivantes:

#!/usr/bin/env python
import sys

from PyQt4 import QtGui, uic

app = QtGui.QApplication(sys.argv)
# On applique ici un style par défaut à notre fenetre
QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
widget = uic.loadUi("djangotextwriter.ui")
widget.show()

# La boucle principale
app.exec_()

Cette méthode permet d’afficher et de tester rapidement les dialogues générés par QtDesigner. Néanmoins, elle est assez limitée dans la mesure où il est généralement nécessaire d’ajouter du code pour les slots présents dans la forme. Cette approche devra dans ce cas être délaissée pour une des deux suivantes.

Par dérivation de la classe QmainWindow:

On crée ici une classe MonAplli qui dérive de QmainWindow, et on fait en sorte de connecter notre bouton à un slot qui affichera « bonjour » sur la console.

import sys
from PyQt4 import QtGui, QtCore
from ui_principal import Ui_MainWindow

# Le deuxième exemple montre l'approche par héritage
# unique ou l'on sous classe QMainWindow et configurons
# l'interface utilisateur dans la méthode init() :

class MonAppli(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)

        # Configure l'interface utilisateur.
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # Connecte le bouton.
        self.connect(self.ui.pushButton, QtCore.SIGNAL("clicked()"),message)

def message():
    print "bonjour\n"
    return

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = MonAppli()

    window.show()
    sys.exit(app.exec_())

Cette méthode nous permet, en créant une classe héritée de QApplication, de pouvoir rajouter des objets et des méthodes. Contrairement à la méthode simple, notre classe peut se rendre “utile” et non seulement afficher un dialogue inerte.

Par dérivation multiples des classes QmainWindow et Ui_MainWindow:

import sys
from PyQt4 import QtGui, QtCore
from ui_principal import Ui_MainWindow

# Le troisieme exemple montre l'approche par héritage multiple
# unique ou l'on sous classe QMainWindow et configurons
# l'interface utilisateur dans la méthode init() :

class MonAppli(QtGui.QMainWindow, Ui_MainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)

        # Configure l'interface utilisateur.
        self.setupUi(self)


        # Connecte le bouton.
        self.connect(self.pushButton, QtCore.SIGNAL("clicked()"),message)

def message():
    print "bonjour"
    return

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = MonAppli()

    window.show()
    sys.exit(app.exec_())

Cette dernière méthode permet un accès direct aux objets de l’interface dont la manipulation devient bien plus simple. Elle ne permet pas d’intégrer des interfaces multiples.

Conclusion:

Nous voici à la fin de ce petit tutoriel, j'espère qu'il vous sera utile.

Kib.