Mini-cours de Python

Interfaces Graphiques

Il existe deux types de module. Ceux installés avec l'installation de Python et ceux à installer après l'installation de Python.

Module Tkinter - aperçu

L'avantage du module tkinter est qu'il ne doit pas être installé, il est compris dans l'installation de Python. De plus, il est suffisant pour débuter.

Nous avons vu le code d'un programme pour afficher le nom des fichiers correspondant à un mot-clé. Transformons, ce programme en logiciel.

Il nous faut donc créer une interface graphique, avec :

Ci-dessous le code pour afficher cette interface

import tkinter         # import de tkinter

root = tkinter.Tk ()   # création de la fenêtre principale

# Création des objets contenu dans la fenêtre
txt_nomDB = tkinter.Entry ()
btn_open = tkinter.Button (text = "Ouvrir")
txt_keyword = tkinter.Entry ()
btn_search = tkinter.Button (text = "Chercher")
lbl_result = tkinter.Label ()
btn_clear = tkinter.Button (text = "Effacer")
btn_quit = tkinter.Button (text = "Quitter")

# Positionnement des objets
txt_nomDB.grid (row = 0, column = 0)
btn_open.grid (row = 0, column = 1)
txt_keyword.grid (row = 1, column = 0)
btn_search.grid (row = 1, column = 1)
lbl_result.grid (row = 2, column = 0)
btn_clear.grid (row = 2, column = 1)
btn_quit.grid (row = 3, column = 1)

# Définitions des actions sur un bouton
def ouvrir() :
  #...
btn_open.config (command = ouvrir)

def quitter() :
  #...
  root.destroy()   # fermeture de la fenêtre
btn_quit.config (command = quitter)

def effacer() :
  lbl_result.config (text = "")
  txt_keyword.delete (0, len(txt_keyword.get()))
btn_clear.config (command = effacer)

def chercher() :
  #...
btn_search.config (command = chercher)

root.mainloop ()       # affichage de la fenêtre

Rappel : Le but est vous donner une idée du code (et non de vous expliquer ce code)

Lorsque ce code est exécuté, s'affiche :

En l'état, la seule chose possible est de fermer le logiciel en cliquant sur (et d'effacer le mot-clé tapé).

Pour finir, on peut s'inspirer du code du programme pour compléter le code relatif aux actions des boutons : Ouvrir, Quitter et Chercher.

import tkinter
import sqlite3
import os.path

# Déclaration des variables globales
root = tkinter.Tk ()   # création de la fenêtre principale
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
con = 0; cur = 0

# Création des objets contenu dans la fenêtre
txt_nomDB = tkinter.Entry ()
btn_open = tkinter.Button (text = "Ouvrir")
txt_keyword = tkinter.Entry ()
btn_search = tkinter.Button (text = "Chercher")
lbl_result = tkinter.Label ()
btn_clear = tkinter.Button (text = "Effacer")
btn_quit = tkinter.Button (text = "Quitter")

# Positionnement des objets
txt_nomDB.grid (row = 0, column = 0)
btn_open.grid (row = 0, column = 1)
txt_keyword.grid (row = 1, column = 0)
btn_search.grid (row = 1, column = 1)
lbl_result.grid (row = 2, column = 0)
btn_clear.grid (row = 2, column = 1)
btn_quit.grid (row = 3, column = 1)

# Définitions des actions sur un bouton
def ouvrir() :
  CC = os.path.join(BASE_DIR, txt_nomDB.get())
  global con; con = sqlite3.connect(CC)
  global cur; cur = con.cursor()
btn_open.config (command = ouvrir)

def quitter() :
  con.close()     # ferme la base de données
  root.destroy()  # La fenêtre ne se ferme pas si une erreur survient avant ...
btn_quit.config (command = quitter)

def effacer() :
  lbl_result.config (text = "")
  txt_keyword.delete (0, len(txt_keyword.get()))
btn_clear.config (command = effacer)

def chercher() :
  mot_cle=txt_keyword.get()
  mot_cle=mot_cle.replace('"','')  # " est un caractère interdit
  cur.execute("SELECT nomFichier FROM jpg WHERE description like \"%"+mot_cle+"%\";")
  lbl_result.config (text = cur.fetchall())
btn_search.config (command = chercher)

root.mainloop ()       # affichage de la fenêtre

Par rapport au programme, le nombre de lignes de code a doublé. Et, ce n'est pas fini. Il faudrait encore coder pour interdire à l'utilisateur certains comportements 

  • Quitter avant d'avoir ouvert une base de données
  • Chercher avant d'avoir ouvert la base de données
  • ...

De plus, de nombreuses améliorations fonctionnelles peuvent être faites. Notamment, en remplaçant le champ de saisie du chemin du fichier à ouvrir par une boîte de dialogue.


Le module tkinter admet des extensions.

tix

Depuis janvier 2017, ce module ne devrait plus être importé.

Deprecated since version 3.6: This Tk extension is unmaintained and should not be used in new code. Use tkinter.ttk instead.

ttk

Cette extension du module tkinter améliore l'apparence et ajoute des nouveaux widgets

Ttk comes with 18 widgets, twelve of which already existed in tkinter: Button, Checkbutton, Entry, Frame, Label, LabelFrame, Menubutton, PanedWindow, Radiobutton, Scale, Scrollbar, and Spinbox. The other six are new: Combobox, Notebook, Progressbar, Separator, Sizegrip and Treeview. And all them are subclasses of Widget.


D'autres améliorations visuelles peuvent être faites : boutons de même taille, objets ne collant pas aux bords, couleurs, dimensions des objets si la fenêtre est agrandie, ...

On constate que pour être agréable, le nombre de lignes de code (et donc de risques d'erreur) augmente vite. Plus c'est agréable pour l'utilisateur, plus c'est difficile pour le développeur.

Les objets créés avec le module tkinter sont moins esthétiques que ceux de PyQt5. Pour faire plus joli, il faut installer un module tel que PyQt5.

Les modules non-installés lors de l'installation de Python sont généralement installés via PIP.

PIP

PIP est un gestionnaire de modules (inclus par défaut depuis Python 3.4)

Documentation

Vérifier si PIP est installé
C:\Users\xxx\AppData\Local\Programs\Python\Python39\Scripts>pip --version

Avant d'utiliser PIP,

  1. Vérifiez qu'il est à jour

    python.exe -m pip install --upgrade pip

    Ce code est lancé depuis un terminal (ouvert dans n'importe quel dossier).

  2. Installer le module

    Installation d'un module (ici, camelcase) :

    C:\Users\Your Name\AppData\Local\Programs\Python\Python39\Scripts>pip install camelcase

Les modules qui peuvent être installés sont officiels ou pas.

Listing des modules "officiels"

Listing des modules installés => pip list

Ce code est lancé depuis un terminal (ouvert dans n'importe quel dossier, après installation de PIP).

Désinstaller un module

(N'importe quel dossier)   >py -m pip uninstall pydash
Found existing installation: pydash 6.0.2
Uninstalling pydash-6.0.2:
  Would remove:
    c:\users\Your Name\appdata\local\programs\python\python39\lib\site-packages\pydash-6.0.2.dist-info\*
    c:\users\Your Name\appdata\local\programs\python\python39\lib\site-packages\pydash\*
Proceed (Y/n)? Y
  Successfully uninstalled pydash-6.0.2

Module PyQt5 - aperçu

PyQt n'est pas un module officiel. La version 6, PyQt6, existe.
Qt est aussi souvent utilisé avec un autre langage, le C++.

Il existe des tutoriels :

Installations

Dans C:\Users\Your Name\AppData\Local\Programs\Python\Python39\Scripts> :

pip3 install PyQt5
pip3 install pyqt5-tools

Premier programme

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class window(QWidget):
   def __init__(self, parent = None):
      super(window, self).__init__(parent)
      self.resize(200,50)
      self.setWindowTitle("PyQt5")              # titre de la fenêtre
      self.label = QLabel(self)
      self.label.setText("Bonjour, Thibaut !")  # contenu du 'label'
      font = QFont()
      font.setFamily("Times New Roman")         # choix de la police
      font.setPointSize(16)                     # taille du texte
      font.setItalic(True)                      # mise en italique
      self.label.setFont(font)
      self.label.move(15,20)                    # position du 'label'
      self.label.setStyleSheet("color:red")     # couleur du texte
def main():
   app = QApplication(sys.argv)
   ex = window()
   ex.show()
   sys.exit(app.exec_())
if __name__ == '__main__':
   main()

S'affiche :

Qt5 dispose d'objets plus raffinés, plus nombreux et plus paramétrables que ceux du module tkinter. Plus d'info sur Qt5 for Python

Qt5 contient à lui seul plus de 20 modules, dont les plus utilisés sont : QtCore, QtGui et QtWidgets.

Qt Designer

Qt Designer est un logiciel qui vous permet de créer facilement l'interface de votre logiciel.

Lancement de Qt Designer

Dans le dossier où Python a été installé (sous Windows), faites une recherche sur "designer.exe"

Exemple d'emplacement :

C:\Users\Your_name\AppData\Local\Programs\Python\Python39\Lib\site-packages\qt5_applications\Qt\bin

Après le lancement de Qt Designer, on peut choisir de créer une "MainWindow".

Les objets s'affichent à gauche. Après avoir glissé un objet sur l'interface à construire (dans la partie centrale), s'affichent à droite toutes les propriétés et méthodes de cet objet.

Après avoir dessiné l'interface de votre logiciel, vous pouvez l'enregistrer.

Le fichier ainsi créé est au format XML et d'extension .ui
L'interface ainsi créée pourra aussi être utilisée dans un autre langage, tel que C++

Pour être utilisé avec Python, il doit être traduit grâce à pyuic5.

Lancement de pyuic5

Dans le dossier où Python a été installé (sous Windows), faites une recherche sur "pyuic5"

Exemple d'emplacement :

C:\Users\Your_name\AppData\Local\Programs\Python\Python39\Scripts

Vous pouvez enregistrer votre fichier .ui dans ce dossier. Après avoir lancé le CLI de Windows (cmd) dans ce dossier, il suffira alors de taper semblable à :

pyuic5 demo.ui -o demo.py

pour vous éviter de taper, si votre fichier .ui est dans un autre dossier, sous Windows :

pyuic5 -x C:\Users\Your_name\Desktop\Divers\pythonTests\demo.ui -o C:\Users\Your_name\Desktop\Divers\pythonTests\demo.py

ou, sous Linux :

pyuic5 /home/linux/demo.ui -o demo.py

Code Python généré (à notre place, par pyuic5)

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

# Form implementation generated from reading ui file 'searchPhotos.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(454, 316)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(20, 20, 201, 23))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(240, 60, 91, 23))
        self.pushButton_2.setObjectName("pushButton_2")
        self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_3.setGeometry(QtCore.QRect(350, 60, 81, 23))
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_4.setGeometry(QtCore.QRect(350, 20, 81, 23))
        self.pushButton_4.setObjectName("pushButton_4")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(20, 60, 201, 21))
        self.lineEdit.setObjectName("lineEdit")
        self.listWidget = QtWidgets.QListWidget(self.centralwidget)
        self.listWidget.setGeometry(QtCore.QRect(20, 100, 411, 171))
        self.listWidget.setObjectName("listWidget")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Trouver des photos"))
        self.pushButton.setText(_translate("MainWindow", "Ouvrir une base de données (.db)"))
        self.pushButton_2.setText(_translate("MainWindow", "Rechercher"))
        self.pushButton_3.setText(_translate("MainWindow", "Effacer"))
        self.pushButton_4.setText(_translate("MainWindow", "Quitter"))
        self.lineEdit.setPlaceholderText(_translate("MainWindow", "Mot-clé"))


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

Une fois le code interprété, s'affiche alors :

À ce stade, le logiciel ne fait rien. Les trois boutons utiles sont ceux présents dans tout logiciel : la croix de fermeture, le carré d'agrandissement, le trait de réduction totale.

Pour que le logiciel réagisse aux actions de l'utilisateur, je vous invite maintenant à lire la documentation et notamment :
PyQt5 - Signals & Slots

Plus c'est joli, plus il faut coder ...
Pour créer des outils, tkinter tel que livré est suffisant.

Tkinter - en détail