Utilisons la POO !

Enfin, la voilà, la grande POO. Je vous en parle depuis le début de ce cours, je pense qu’il serait enfin temps de s’y coller, non ?

Les exercices vont enfin pouvoir devenir un peu plus intéressant ! :D

Comment ça se présente ?

Nous allons utiliser l’héritage ici. J’espère que vous êtes au point sur ce concept très puissant.

Imaginons que vous voulez créer un logiciel. Il vous faudra une fenêtre, n’est-ce pas ? Nous allons donc créer une classe pour cette fenêtre qui héritera de Gtk.Window. Nous aurons ainsi accès à toutes ses propriétés, méthodes et signaux. Mais là où ça devient intéressant, c’est que l’on va pouvoir rajouter les notre ! Vous commencez à imaginer les possibilités ? Toujours pas !? Peut-être qu’une petite démonstration vous aiderait.

J’ai donc repris notre hello world.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from gi.repository import Gtk


class HelloWorld(Gtk.Window):

    def __init__(self):
        '''
        Le constructeur de notre classe HelloWorld
        '''
        # On utilise le constructeur de Gtk.Window
        Gtk.Window.__init__(self, title='Hello world!')

        # On créer notre label, rien de nouveau ici
        label = Gtk.Label('Hello world!')

        # On l'ajoute à notre fenêtre, cette fenêtre
        self.add(label)


# On créer notre application
app = HelloWorld()
app.show_all()

Gtk.main()

Certes vous ne voyez peut-être toujours pas l’intérêt de la POO ici, à part que je trouve que le code est bien plus clair. Mais si je fais ça :

 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
from gi.repository import Gtk


class HelloWorld(Gtk.Window):

    def __init__(self):
        '''
        Le constructeur de notre classe HelloWorld
        '''
        # On utilise le constructeur de Gtk.Window
        Gtk.Window.__init__(self, title='Hello world!')
        self.connect('delete-event', Gtk.main_quit)
        self.set_border_width(10)

        layout = Gtk.Grid()
        layout.set_column_spacing(6)
        layout.set_row_spacing(6)

        # On fait un attribut pour y avoir accès partout
        self.clics_counter = 0

        self.label = Gtk.Label('Comment t\'appelles-tu ?')

        self.entry = Gtk.Entry()
        self.entry.connect('activate', self.on_validate)  # Si l'utilisateur appuie sur <Entrée>

        self.button = Gtk.Button(label='Valider')
        self.button.connect('clicked', self.on_validate)

        layout.attach(self.label, 0, 0, 1, 1)
        layout.attach(self.entry, 1, 0, 1, 1)
        layout.attach(self.button, 1, 1, 1, 1)

        self.add(layout)
        self.show_all()


    def on_validate(self, widget):
        '''
        Quand le champ de texte est validée
        '''
        # On fait tout d'un coup, on ne perd pas de temps ici ! :p
        self.label.set_text('Salut {} !'.format(self.entry.get_text()))
        self.entry.set_text('')

        # Pas besoin d'une variable globale à déclarer
        self.clics_counter += 1
        # On accorde correctement le mot "clic"
        if self.clics_counter > 1:
            self.button.set_label('Vous en êtes à {} clics'.format(self.clics_counter))
        else:
            self.button.set_label('Vous en êtes à {} clic'.format(self.clics_counter))


# On créer notre application
app = HelloWorld()
Gtk.main()

Si vous en avez l’envie, faite la même chose sans POO, vous verrez que le code est beaucoup moins lisible. De plus, imaginez que vous faîtes un programme avec plein de fenêtres : vous allez pouvoir faire une classe pour chaque fenêtre. Par la suite vous aurez juste à faire interagir ces classes. Regardez comment c’est simple de créer une fenêtre maintenant :

1
2
app = HelloWorld()
Gtk.main()

Et rien ne vous empêche d’en faire plus !

1
2
3
4
app = HelloWorld()
app_2 = HelloWorld()

Gtk.main()

Maintenant que vous avez votre moule, vous pouvez faire autant de gâteaux que vous voulez. ;)

Comment l'utiliser ?

Voilà, cette partie est presque terminée. Elle était en effet très courte, la prochaine partie sur Glade viendra la compenser.

Pour terminer, j’aimerais que l’on s’attarde sur comment bien utiliser la POO. Il existe en effet plusieurs façons de résoudre un problème dans une interface graphique, grâce à ce paradigme. Je vais donc vous présenter ma vision de la chose. Elle tient en un seul et unique mot, décomposez.

Une classe héritant de Gtk.Window peut être extrêmement lourde si on ne la décompose pas. Il est donc important d’identifier les différentes parties de votre logiciel et donc de réfléchir à l’interface avant, sur papier. Évidement, ces conseils ne s’appliquent que pour des interfaces lourdes, comme celle de la figure suivante par exemple.

Un exemple d’interface complexe

Si celle-ci tenait en une seule classe, ce serait imbuvable et infecte d’effectuer la moindre modification. En fait, elle tient en 3 parties – et donc trois classes dans le code – qui interagissent entre elles. Je vous ai représenté les 3 parties sur cette figure :

Les 3 parties du programme, de différentes couleurs

Vous voyez donc que j’ai une première partie en vert et une autre en rouge qui sont incluses dans celle en bleu, la fenêtre. Le plus dur étant de réussir à les faire interagir entre elles, ce qui viendra avec de l’expérience.

Au final, n’hésitez pas à faire hériter vos classes d’un layout comme Gtk.Grid plutôt que d’une fenêtre. Vous ajoutez ensuite ce layout à un autre layout qui lui contient tout ceux de votre fenêtre. Petit exemple :

1
2
3
4
5
6
7
class GrilleAvecBoutons(Gtk.Grid):
    def __init__(self):
        Gtk.Grid.__init__(self)

        btn = Gtk.Button(label="Mon super bouton")
        self.attach(0, 0, 1, 1)
        # exétéra
Fichier n°1 : une grille pour piloter l’application

Comme on a aussi besoin d’un conteneur principal :

1
2
3
4
5
6
7
8
9
class MainWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)

        box = Gtk.Box()
        sublayout = GrilleAvecBouton()

        box.pack_start(sublayout, True, True, 0)
        self.add(box)
Fichier n°2 : la fenêtre qui les gouverne toutes

Ce code n’est évidement pas fonctionnel, c’est juste une petite démonstration.


Voilà vous savez tout !

J’imagine que vous en avez un peu marre de devoir tout coder. Les développeurs de GTK étant, eux aussi, des flemmards (n’est ce pas ce qui fait l’ADN d’un développeur ?) ont codé un constructeur d’interface, Glade. Je vous le présente au prochain chapitre !