Des interfaces graphiques en Python et GTK

Utilisez Gtk+ 3 pour améliorer vos programmes Python 3

Les interfaces graphiques vous en voyez tout le temps, sans même y penser. En effet, ce sont ces fenêtres avec des boutons, des menus, des champs de texte… Et si vous appreniez comment en faire ? Vous allez voir que ce n’est pas aussi compliqué que ce que vous pouvez le penser, et même si la console permet de faire des choses vraiment très poussé en terme d’interface, un utilisateur lambda sera bien plus à l’aise avec une interface graphique ! Vous êtes prêt à traverser la fenêtre ? ;)

Vous êtes alors le/la bienvenue dans ce cours. Je vais vous montrer comment utiliser GTK+ 3, à travers un binding1 python de GObject sur lequel se base GTK+ 3 (oui c’est un peu compliqué, mais je vous promet que ça fonctionne !), afin de créer votre propre interface graphique.

Pour suivre ce tutoriel, il vous sera évidemment conseillé d’avoir une bonne connaissance de Python. La programmation d’interface graphique apporte son lot de problème que l’on avait pas avec la console. Celle-ci effectuait une suite d’action dans l’ordre définie par vous, le programmeur. Une interface graphique exécute les instructions dans l’ordre que l’utilisateur choisi. C’est à vous de penser à tous les cas.

Ça peut paraître effrayant comme ça, mais ne vous inquiétez pas, PyGObject nous simplifie grandement la vie. On commence ? :pirate:


  1. Un binding est le portage d’une bibliothèque écrite avec un certain langage vers un nouveau langage. En effet, GObject est écrite en C mais nous allons l’utiliser avec Python. 

Découverte

  1. Installation

    1. Sous Linux

    2. Sous Windows

    3. Vérification de l'installation

    4. Comment lire la documentation

  2. Une première fenêtre, le Hello world

    1. Avec l'interpréteur

    2. La boucle GTK

    3. Un peu d'exercice

  3. Les événements

    1. Présentation

    2. Premier contact

    3. La notion d'événement

    4. Entrainons-nous

  4. Le positionnement grâce aux layouts

    1. Introduction

    2. Les boîtes

    3. Les grilles

    4. Un compteur de clics

  5. À la découverte de nouveaux widgets !

    1. Les propriétés

    2. Les labels

    3. Les champs de texte

    4. Les toggleButtons et les switchs

    5. Les images avec Pixbuf

    6. Les calendriers

  6. [TP] Le jeu du plus ou moins

    1. Consignes

    2. Correction

    3. Améliorations

Utilisation avancée

  1. Utilisons la POO !

    1. Comment ça se présente ?

    2. Comment l'utiliser ?

  2. Prise en main de Glade

    1. Installation

    2. Présentation

    3. Utiliser Glade avec Python



Waouh, on en aura parcouru du chemin ensemble !

Vous voilà capable de créer des interfaces graphiques, de la plus simple à la plus compliquée. Vous en voulez-encore ? Explorez les différents widgets que vous propose PyGObject, ou créez carrément le vôtre !

11 commentaires

Bonsoir je n’arrive pas à programmer un bouton qui réagit par défaut suite a un appui sur touche enter dans le code qui suit après cette explication quand on utilise directement des boutons simples comme ceci

1
2
3
_buttons = ((gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OK,gtk.RESPONSE_OK))
window = gtk.Dialog('Saisie de texte', None,buttons = _buttons)
window.set_default_response(Gtk.ResponseType.OK) 

j’obtiens bien le bouton gtk.STOCK_OK préactivé et qui réagit à un enter

en revanche pour l’autre façon de gérer les boutons par add_action_widget je ne trouve pas la commande qu’il faut dans le code ci dessous c’est le bouton help et en général le bouton le + à gauche qui prend systématiquement cette option et je ne maîtrise pas du tout l’ordre d’affichage des widgets bizarre !!!!

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
```py
#!/usr/bin/env python
#!/usr/bin/env python
# coding: utf-8 
# coding: utf-8 
#test_dialog_defaultbutton.py
#test_dialog_defaultbutton.py
from gi.repository import Gtk
from gi.repository import Gtk


class boite_stockicon_etiquette:
class boite_stockicon_etiquette:
    ''' box with STOCK Icon '''
    ''' box with STOCK Icon '''
    def __init__(self,text, stock_icon=None,sizeicon=Gtk.IconSize.MENU):
    def __init__(self,text, stock_icon=None,sizeicon=Gtk.IconSize.MENU):
        # On cree une boite pour la pixmap et l'etiquette
        # On cree une boite pour la pixmap et l'etiquette
        self.box = Gtk.HBox(False, 0)
        self.box = Gtk.HBox(False, 0)
        self.box.set_border_width(2)
        self.box.set_border_width(2)
        # A present l'image.
        # A present l'image.
        if stock_icon is not None:
        if stock_icon is not None:
            image = Gtk.Image.new_from_stock(stock_id=stock_icon,size=sizeicon)             
            image = Gtk.Image.new_from_stock(stock_id=stock_icon,size=sizeicon)             
        else:
        else:
            image = Gtk.Image.new_from_stock(stock_id=Gtk.STOCK_OK,size=sizeicon)                 
            image = Gtk.Image.new_from_stock(stock_id=Gtk.STOCK_OK,size=sizeicon)                 
        # On cree une etiquette pour le bouton.
        # On cree une etiquette pour le bouton.
        etiquette = Gtk.Label(text)
        etiquette = Gtk.Label(text)
        # pack image and label in the box
        # pack image and label in the box
        self.box.pack_start(image, False, False, 3)
        self.box.pack_start(image, False, False, 3)
        self.box.pack_start(etiquette, False, False, 3)
        self.box.pack_start(etiquette, False, False, 3)
    
    
    def box_xpm(self):
    def box_xpm(self):
        return self.box 
        return self.box 


class dialogDefaultButton:
class dialogDefaultButton:
    """ make button with stock icon"""
    """ make button with stock icon"""
    def _make_button(self,etiquette=None,stock_icon=None):
    def _make_button(self,etiquette=None,stock_icon=None):
        boite1= boite_stockicon_etiquette(etiquette,stock_icon=stock_icon)
        boite1= boite_stockicon_etiquette(etiquette,stock_icon=stock_icon)
        boite = boite1.box_xpm()
        boite = boite1.box_xpm()
        bouton = Gtk.Button()    
        bouton = Gtk.Button()    
        bouton.add(boite)    
        bouton.add(boite)    
        return bouton    
        return bouton    


    def __init__(self,text):
    def __init__(self,text):
        self.dialog = Gtk.Dialog(title="Dialog")
        self.dialog = Gtk.Dialog(title="Dialog")


        self.dialog.set_default_size(400, 300)
        self.dialog.set_default_size(400, 300)
        self.dialog.set_border_width(10)
        self.dialog.set_border_width(10)


        self.dialog.add_action_widget(self._make_button(etiquette=u'Valid',stock_icon=Gtk.STOCK_OK),Gtk.ResponseType.OK)   
        self.dialog.add_action_widget(self._make_button(etiquette=u'Valid',stock_icon=Gtk.STOCK_OK),Gtk.ResponseType.OK)   
        self.dialog.add_action_widget(self._make_button(etiquette=u'Cancel',stock_icon=Gtk.STOCK_CANCEL),Gtk.ResponseType.CANCEL)
        self.dialog.add_action_widget(self._make_button(etiquette=u'Cancel',stock_icon=Gtk.STOCK_CANCEL),Gtk.ResponseType.CANCEL)


        #Please test under with True ou False
        #Please test under with True ou False
        flag_button_valide_setdefault = False
        flag_button_valide_setdefault = False


        #if flag_button_valide_setdefault is True the valid button is set like self.dialog.set_default_response(Gtk.ResponseType.OK)
        #if flag_button_valide_setdefault is True the valid button is set like self.dialog.set_default_response(Gtk.ResponseType.OK)
        if flag_button_valide_setdefault is not True:
        if flag_button_valide_setdefault is not True:
            self.dialog.add_action_widget(self._make_button(etiquette=u'Add', stock_icon=Gtk.STOCK_ADD),Gtk.ResponseType.APPLY)
            self.dialog.add_action_widget(self._make_button(etiquette=u'Add', stock_icon=Gtk.STOCK_ADD),Gtk.ResponseType.APPLY)
            self.dialog.add_action_widget(self._make_button(etiquette=u'Help', stock_icon=Gtk.STOCK_ABOUT),Gtk.ResponseType.HELP)
            self.dialog.add_action_widget(self._make_button(etiquette=u'Help', stock_icon=Gtk.STOCK_ABOUT),Gtk.ResponseType.HELP)


        label = Gtk.Label(text)
        label = Gtk.Label(text)


        content_area = self.dialog.get_content_area()
        content_area = self.dialog.get_content_area()
        content_area.add(label)
        content_area.add(label)
        self.dialog.show_all()
        self.dialog.show_all()
        #Here action do not run ok why ?
        #Here action do not run ok why ?
        # Ok only with button created with   add_button
        # Ok only with button created with   add_button






    def run(self):
    def run(self):
        while 1:  
        while 1:  
            self.reponse = self.dialog.run()
            self.reponse = self.dialog.run()
            if self.reponse in [Gtk.ResponseType.OK, Gtk.ResponseType.CANCEL,Gtk.ResponseType.DELETE_EVENT]:
            if self.reponse in [Gtk.ResponseType.OK, Gtk.ResponseType.CANCEL,Gtk.ResponseType.DELETE_EVENT]:
                print("OK sa marche button clicked")
                print("OK sa marche button clicked")
                print self.reponse
                print self.reponse
                break
                break
            else:
            else:
                print 'Hello'
                print 'Hello'


        self.dialog.destroy()         
        self.dialog.destroy()         
        return self.reponse
        return self.reponse


if __name__ == "__main__":
if __name__ == "__main__":
    demo = dialogDefaultButton(text= u'demo of default button depend widget list why?\n\
    demo = dialogDefaultButton(text= u'demo of default button depend widget list why?\n\
\n\
\n\
if flag_button_valide_setdefault == True , \n\
if flag_button_valide_setdefault == True , \n\
the valid button is set like self.dialog.set_default_response(Gtk.ResponseType.OK)\n\
the valid button is set like self.dialog.set_default_response(Gtk.ResponseType.OK)\n\
if flag_button_valide_setdefault == False \n\
if flag_button_valide_setdefault == False \n\
\n\
\n\
if somebody could help me to understand what is about !!!!!\n\
if somebody could help me to understand what is about !!!!!\n\
in fact I need to have flag_button_valide_setdefault =False\n\
in fact I need to have flag_button_valide_setdefault =False\n\
and the valid button set with default response like case of flag==True')
and the valid button set with default response like case of flag==True')
    response = demo.run()
    response = demo.run()
    if response == Gtk.ResponseType.OK:
    if response == Gtk.ResponseType.OK:
        print("OK button clicked")
        print("OK button clicked")
    elif response == Gtk.ResponseType.CANCEL:
    elif response == Gtk.ResponseType.CANCEL:
        print("Cancel button clicked")
        print("Cancel button clicked")
    else:
    else:
        print("Dialog closed")
        print("Dialog closed")

une idée ? merci d’avance de votre aide

Édit (par Taurre) : mise du code sous balises « secret ».

+0 -0

Comme le dit Matouche :

Merci beaucoup pour ce tuto ! J’avais essayé de m’y mettre il y a quelques mois, mais c’était galère de trouver une ressource autre que la doc (pas super accueillante de prime abord), parce que la plupart des cours en ligne sont encore sous pygtk.


Comptes-tu rajouter des chapitres à ce tuto ? J’ai deux sujets qui me viennent en tête : les TreeViews et les Applications. Les deux sujets sont velus, et, armé de la doc uniquement, c’est pas facile !

+2 -0

Je suggère de préciser dans cet excellent tuto sur GTK+ que pour Python 3, il doit être installé sur Python 3.4 uniquement.
La doc du projet explique qu’il ne sera jamais porté sur Python 3.5.
Quant à Python 3.6, ça ne marche pas non plus.

+0 -0

Il existe un paquet pip qui permet d’installer ces bindings : pgi

Ils semble être supporté par les versions supérieures de Python. Ça peut être une bonne idée de les ajouter comme procédure d’installation.

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte