Les gestionnaires graphiques dans Python¶
- Auteur:
J.Soranzo
- Entity:
- Création:
12/2023
- Maj:
12/2023
Gestionnaires graphiques¶
tkinter¶
Voir fichiers Freeplane. Todo: convertir en rst en cour ci-dessous
pyQt5¶
Voir fichiers Freeplane. Todo: convertir en rst
Pysimplegui¶
Voir fichiers Freeplane. Todo: convertir en rst (et encore j’ai jsute mis une ligne pour m’en rappeler)
tkInter¶
Docs¶
Super doc en pdf du site New Mexico Tech <http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html>
téléchargé <../03-Cours_Docs/programmation/Python/tkinter.pdf>
on WDD
C'est surtout la doc de tlc/tk qui est importante
tkinter est juste un wrapper entre Python et tcl/tk
Correction 6/7/15, grace à ce doc, la doctcl/tk devient moins nécessaire
Surtout que la gym du wrapper n'est pas simple
C'est surtout un ref doc sans exemple
Chapitre 27 à reconsidérer 6/11/2020
tkinter rérérence <https://web.archive.org/web/20190524140835/https://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html>
JohnW. Shipman
Super doc en pdf du site New Mexico Tech
pdf dans coursEtDoc/programmation/python
JohnW. Shipman
DOC Officielle <https://docs.python.org/fr/3/library/tkinter.html>
Trucs et astuce¶
Astuce tkInter:
Lier un fonction à un bouton par une fonction lambda permet de passer des paramètres à la callback utilisée
Truc rigolo
tkinter._test()
Outils¶
Il existe un tkinterdesigner qui se nomme Page
http://page.sourceforge.net/
Je l'ai téléchargé et installé (MSI 08/2020)
redo en 12/07/2022 sur le MSI
J'ai eu un peu de mal à le lancer
winpage.bat
double click dessus
Cela fonctionne si on suit le tuto du pdf. J'ai juste créé un bouton
où ?
Dans le répertoire doc
Mais je me demande si je ne préfère pas faire à la main !
le répertoire examples est bien fourni
s'install directement en c:/page
essais
C:\MountWD\Donnees\ODJ\008_iao_wrk\Python\experimentations\tkinter_exemples\pageUiDesigner
08/2020
intéressant pour expérimenter des Widget
Structuration¶
tkinter c'est <https://docs.python.org/3.4/library/tkinter.html#tkinter-modules>
17 Widgets
Button
Canvas
A canvas is a rectangular area intended for drawing pictures or other complex layouts. On it you can place graphics, text, widgets, or frames.
Checkbutton
Entry
Frame
A frame is basically just a container for other widgets.
Frame widgets are a valuable tool in making your application modular. You can group a set of related widgets into a compound widget by putting them into a frame.
Label
LabelFrame
Listbox
Menu
Menubutton
Message
This widget is similar to the Label widget but it is intended for displaying messages over multiple lines.
OptionMenu
Radiobutton
Scale
Scrollbar
Spinbox
Text
Text widgets are a much more generalized method for handling multiple lines of text than the Label widget. Text widgets are pretty much a complete text editor in a window
+ttk qui
Redéfini des Wgts et en défini 4 nouvx
import tkinter as tk
from tkinter import ttk
Sauvegarde l'espace de nom de tkinter donc:
on utilise la syntaxe ttk.wdg
• Section 31, “ttk.Combobox” (p. 115).
• Section 37, “ttk.Notebook” (p. 126).
• Section 39, “ttk.Progressbar” (p. 130).
• Section 43, “ttk.Separator” (p. 137)
Les autres sont mis à la sauce de l'interface graphique de la plateform
13 sous package ou modules
import tkinter.messagebox
import tkinter.filedialog
PACKAGE CONTENTS
colorchooser
commondialog
constants
dialog
dnd
filedialog
font
messagebox
scrolledtext
simpledialog
test (package)
tix
ttk
Des méthodes communes
3 gestionnaires de géométrie différents <http://effbot.org/zone/tkinter-geometry.htm>
pack
.pack() empile les widget sur une colonne centrée les uns aux dessus des autres dans le widget parent
.pack(fill=X ) permet de prendre toute la largeur duparentWidget
de même avec fill=Y pour la verticale
.pack( side = LEFT ) permet d'aligner les wdg depuis la gauche vers la droite
grid
et place
place( x,y )
Une gestion d'événements
Avertissement
tkMessageBox est devenu tkinter.messagebox
- S’appelle au travers de ses méthode
messagebox.askyesnocancel(title= »Hello », message= »coucou »)
- Nécessite de faire :from tkinter import messagebox
(j’ai pas réussi à le faire marcher autrement)
Limitations¶
Ne supporte pas le multithreading
génant pour exécuter une tâche périodique
il y a une méthode applicable à tout widget .after
chapitre 26 du livre sur tkinter.pdf
from tkinter import *
import subprocess
output = subprocess.check_output('sleep 2 ; date', shell=True)
win = Tk()
f1 = Frame( win )
tp = Label( f1 , text='Date: ' + str(output[:-1]))
f1.pack()
tp.pack()
def task():
output = subprocess.check_output('date', shell=True)
tp.configure(text = 'Date: ' + str(output[:-1]))
win.after(2000, task)
win.after(2000, task)
win.mainloop()
le gestionnaire graphique grid à tendance à n'en faire qu'à sa tête pour positionner les objets
utiliser pack, c'est ce que tout le monde fait ou presque
Exemple de limitation: une zone de texte n'a pas de scroll bar automatique (on est obligé de l'ajouter à part)
non voir les autres modules contenu dans la package
Même avec ttk, il reste des manques.
Gestionnaires de geom¶
Il y a 3 gestionnaires de géométrie <#4omhr2i30b381akekijnvatgo6>
To display it, you need to call a special method: either grid, pack (which we’ve used in all examples this far), or place.
pack()
The pack() method mainly uses a packing algorithm in order to place widgets in a Frame or window in a specified order. This method is mainly used to organize the widgets in a block.
3 paramètres seulement fill, expand, side
En vrai, il y en a un peu plus
help (tk.Button.pack)
grid()
The most used geometry manager is grid() because it provides all the power of pack() function but in an easier and maintainable way.
You can easily specify the location of a widget just by calling grid() function and passing the row and column indices to the row and column keyword arguments, respectively
place()
This method basically organizes the widget in accordance with its x and y coordinates. Both x and y coordinates are in pixels
Thus the origin (where x and y are both 0) is the top-left corner of the Frame or the window
Thus, the y argument specifies the number of pixels of space from the top of the window, to place the widget, and the x argument specifies the number of pixels from the left of the window
geom manager utilisé par l'utilitaire Page
site <https://www.studytonight.com/tkinter/python-tkinter-geometry-manager>
Petite recette de cuisine¶
fen = tkinter.Tk()
avec un T majuscule
Dans cette fenêtre on peut alors mettre des Widgets
Comme un Canevas
can = tk.Canvas(fen, width = 400, height= 200, bg = 'ivory')
can.pack()
ou un Frame
Dans le frame on peut mettre des button un autre Frame...
ou un Button
Snippet pour un bouton:
bout = tkinter.Button(fen, text='le text du bouton', command = fen.destroy)
à noter qu'à la fin on ne met pas de paranthèse à la méthode destroy, on passe son adresse à la fonction
à la place de destroy, on peut utiliser quit
quit permet de quitter le gestionnaire d'événement mais ne détruit pas la fenêtre
Cette méthode sert à fermer (quitter) le réceptionnaire d’événements (mainloop) associé à cette fenêtre.
et surtout après bout.pack()
ou bout.grid(row=i, column=j)
Canvas versus frame¶
A Frame is designed to be a container for other widgets. It really doesn’t do anything but provide a border and color, and to collect a set of widgets into a logical group.
A Canvas is something that can act as a container for other widgets (as can just about any widget), but it also has features that let you draw circles, lines, rectangles, and other objects on it.
A Canvas can also be scrolled, whereas a frame cannot.
Appli minimum¶
version non objet
reste à faire...
version objet
2 façons de faire rencontrées lors de mes recherche
façon opneclassroom
on dérive la classe Frame
fenetre = Tk()
interface = Interface(fenetre)
interface.mainloop()
interface.destroy()
façon Object-Oriented Programming in Python <https://python-textbok.readthedocs.io/en/1.0/index.html>
on part de rien
root = Tk()
my_gui = MyFirstGUI(root)
root.mainloop()
Il me semble que la différence est dans l'utilisation
Euh non finalement c'est pareil
Il y a une légère subtilité
qui contient mainloop()
Dans un cas openCr c'est interface et la fenêtre en est un fille
Dans l'autre cas root reste root
Le reste à traiter¶
import tkinter ou from tkinter import*
ou encore import thinker as tk
ensuite on fait systematiquement tk.
http://fsincere.free.fr/isn/python/cours_python_tkinter.php
Event
connection
p157 du pdf
Chapitre 54
tkinter.pdf <file:/C:/MountWD/Donnees/008_iao_wrk/03-Cours_Docs/programmation/Python/tkinter.pdf>
ie binding
w.bind()
w.bind_class()
w.bind_all()
La description de l'événnement est faite grace à une séquence texte
chaine donc ''
La sequence peut contenir plusieurs pattern qui doivent tous être valident pour déclencher le handler (fonction)
Chaque pattern est entouré de <...>
donc de base '<...>'
<[modifier-]...type[-detail]>
types
Button
KeyPress
FocusIn
...
Modifiers
Seulement 7
Alt
ex : Alt-KeyPress-h
<Alt-KeyPress-h>'
Shift
Any
...
-détail
Par exemple le nom des touches
cf p158 du pdf
num bouton souris
You can use shorter forms of the events.
Quelle est la règle exacte ????
revoir les méthodes commune dédiées aux events.
page 99 du pdf sur tkinter
Applimin
exemples
tous les exemples dans le dossier \Python\experimentations\tkinter_exemples sont en code sequentiel
il y a un exemple Oo à la fin du chapitre openclassroom
https://vincent.developpez.com/cours-tutoriels/python/tkinter/apprendre-creer-interface-graphique-tkinter-python-3 <https://vincent.developpez.com/cours-tutoriels/python/tkinter/apprendre-creer-interface-graphique-tkinter-python-3/#LVIII>
pas Oo
https://python-textbok.readthedocs.io/en/1.0/Introduction_to_GUI_Programming.html
Oo
From mindmap (le reste)¶
pyWx:
PyWx
ne supporte pas 3.x
est resté en 2.7
WxPy d'ailleurs
pyQt:
pyQt
Workflow
Installation
un .exe
j'ai des installateur qui date de 2014
v5.3.1
en 2020, il y a un dépôt <https://pypi.org/project/PyQt5/#files>
v5.13.0
Pour vérifier l'installation
>>> from PyQt5.QtWidgets import QApplication, QLabel >>> app = QApplication([]) >>> label = QLabel("Hello World!") >>> label.show() >>> app.exec_()
PyQt is able to generate Python code from Qt Designer.
Mais Qt Designer ne fait pas partie du Pack
si justement !!!
où ?
prendre soit d'installer pyQT5.tools (pip install)
Ensuite on le trouve dans : repertoirInstallPython\Lib\site-packages\pyqt5_tools\Qt\bin
Comment ?
PyQt5 UI code generator 5.3.1
en ligne de commande !!! pyuic5
Avec Qt Designer
On design graphiquement l'interface
Cela produit un fichier .ui
Avec QtDesigner qui produi un fichier .ui
On converti le fichier ui en fichier python avec
pyuic5.bat
dans C:\Python34\Lib\site-packages\PyQt5
Le mieux est de copier le fichier pyuic5.bat dans le répertoire de travail
pas nécessaire PATH redéfini
Commande : pyuic5 toto.ui -o toto.py [-x -i 0]
x genere code de fin
i 0 remplace les espace par des tab
Ne reste plus qu'à mettre en place le cannevas pour l'application
appli min
Version non objet
#!/usr/bin/env python
# coding: utf-8
from PyQt4 import QtGui, QtCore
import sys
app = QtGui.QApplication(sys.argv)
hello = QtGui.QPushButton("Hello World!", None)
hello.show()
app.exec_()
Version objet Qt
grace à pyuic5 on peut avoir automatiquement un semblant d'appel commutateur -x
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
FindAndReplaceDlg = QtWidgets.QDialog()
ui = Ui_FindAndReplaceDlg()
ui.setupUi(FindAndReplaceDlg)
FindAndReplaceDlg.show()
sys.exit(app.exec_())
La création d'une class fille de ui_maBoiteDeDialogue devient alors nécessaire pour ajouter des fonctionnalités/fonctions qui ne sont pas faisables dans QtDesigner
Avec
Les import qui vont bien
la déclaration de la classe fille avec héritage multiple ( QDialog et classe mère ui_...
Avec une fonction __ini__ qui appelle celle de la classe mère (comme pour toute classe fille en python)
role de la fonction super()
lancement également de setupUi()
méthode de la classe fille
Et bien évidement à la fin du fichier un code d'autotest
on peut même y mettre des connection de signaux et plein de code au besoin
if __name__ == "__main__":
app = QApplication(sys.argv)
form = maBoiteDeDialog()
form.show()
app.exec_()
Exemples
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import ui_maBoiteDeDialogue
class classFifille(QDialog,
ui_maBoiteDeDialogue.Ui_maBoiteDeDialogue):
def __init__(self, text, parent=None):
super(classFifille, self).__init__(parent)
self.setupUi(self)
if __name__ == "__main__":
import sys
text = """US experience shows that, unlike traditional patents,
software patents do not encourage innovation and R&D, quite the
contrary. In particular they hurt small and medium-sized enterprises
and generally newcomers in the market. They will just weaken the market
and increase spending on patents and litigation, at the expense of
technological innovation and research. Especially dangerous are
attempts to abuse the patent system by preventing interoperability as a
means of avoiding competition with technological ability.
--- Extract quoted from Linus Torvalds and Alan Cox's letter
to the President of the European Parliament
http://www.effi.org/patentit/patents_torvalds_cox.html"""
def found(where):
print ("Found at %d" % where)
def nomore():
print ("No more found")
app = QApplication(sys.argv)
form = FindAndReplaceDlg(text)
# form.connect(form, SIGNAL("found"), found)
form.found.connect(found)
# form.connect(form, SIGNAL("notfound"), nomore)
form.nofound.connect(nomore)
form.show()
app.exec_()
J'ai créé un modèle d'appli mini dans
C:\MountWD\Donnees\008_iao_wrk\Python\experimentations\appliMiniPyQt <file:/C:/MountWD/Donnees/008_iao_wrk/Python/experimentations/appliMiniPyQt>
Ce qui sommes toute est un wokflow assez lourd
on s'éloigne vite de la simplicité inspirée par Python
Au moins celui là il fonctionne
de plus grâce à Qt Designer on peut plus facilement exploiter la richesse de widget de Qt
La doc officielle est limité au stric référence guide <http://pyqt.sourceforge.net/Docs/PyQt5/>
Grosse liste alphabétique des Class
pas de tuto
Chapitres utiles
Les signaux <http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html>
Signaux prédéfini sur les objects
On peut les connaitre dans QtDesigner
Il y a plusieur façon de connecter un signal à un slot
QtDesigner ne permet pas de faire la connection entre un signal prédéfini et un handler
ou à un handler
grâce à la méthode .connect()
doit être hérité de QtObject
QtCore.QObject.connect(self.ui.button_open,QtCore.SIGNAL("clicked()"), self.file_dialog)
Connection semi-auto aec le décorateur : @pyqtSlot
Signaux utilisateur
On défini un signal
avec pyqtsignal()
On le connect à un handler (un fonction)
signal.connect(fonction)
En l'émet au moment oportun
signal.emit()
Exemple
from PyQt5.QtCore import QObject, pyqtSignal
class Foo(QObject):
# Define a new signal called 'trigger' that has no arguments.
trigger = pyqtSignal()
def connect_and_emit_trigger(self):
# Connect the trigger signal to a slot.
self.trigger.connect(self.handle_trigger)
# Emit the signal.
self.trigger.emit()
def handle_trigger(self):
# Show that the slot has been called.
print "trigger signal received"
quelques uns sur le wiki
Vite redirigé vers la doc de Qt
Tutos qui ont l'air intéressant <http://www.rkblog.rk.edu.pl/w/p/extending-pyqt4-text-editor/>
Conclusion
Le mécanisme fondamental des signaux et slot est lourd
mais très puissant quand il est bien maitrisé
On est quasiment obligé de travailler en objet
Fichier ressource .qrc
stock les images tel les icones cf menu fichier
nécessite un fichier qrc
qui se produit grace à Qt Designer
Ensuite après création, il faut le convertir grâce pyrcc5.exe (comme pour le fichier ui)
Connecting by slot name <http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html>
fonctionnalité puissante de connection automatiques des signaux de l'interface vers des fonction écrite par le codeur
versions
Raspberry pi
pyqt4
Install PyQt4 for Python 3.4 <https://raspberrypi.stackexchange.com/questions/38843/install-pyqt4-for-python-3-4>
gtk+
ne supporte pas 3.x
Peut être utilisé avec Glade
Glade is a RAD tool to enable quick & easy development of user interfaces for the GTK+ toolkit and the GNOME desktop environment.
RAD Rapid Application Developpement
on part gtk3
seulement sous Linux
puis on se retoruve sur PyGObject aka PyGi <https://wiki.gnome.org/action/show/Projects/PyGObject>
et on fini sur une erreur à l'install
pygame
compatible python 3
ça s'install dans la douleur
cela l'est déjà sur Rpi (Jessy)
pysimplegui
12/05/23
A revoir