Outils pour utilisateurs

Outils du site


issue52:tutopython

Last month we discussed tkInter and four of the widgets available: TopLevel, Frames, Buttons, and Labels. I also told you last month, I'd discuss how to have a widget as a parent other than the Toplevel widget. So, this month, we'll discuss more on Frames, Buttons, and Labels, and introduce Checkboxes, Radio buttons, Textboxes (Entry widgets), Listboxes with a vertical scrollbar, and Messageboxes. Before we get started, let's examine some of these widgets. Checkboxes are considered a many of many type selection widget that has two options, checked or not checked, or you could consider it on or off. They are usually used to provide a series of options where any, many, or all of those options may be selected. You can set an event to inform you when the checkbox has been toggled, or just query the value of the widget at any time. Radiobuttons are considered a one of many type selection widget. It also has two options, on and off. However, they are grouped together to provide a set of options that logically can have only one selection. You can have multiple groups of Radiobuttons that, if properly programmed, won't interact with each other.

Le mois dernier, nous avons parlé de TkInter et de quatre des widgets disponibles : la fenêtre principale, les fenêtres, les boutons et les étiquettes (ou labels). Je vous ai également dit le mois dernier que je parlerais de la façon d'avoir un widget autre que le widget de premier niveau comme parent. Aussi, ce mois-ci, nous allons approfondir les fenêtres, les boutons et les étiquettes, et introduire les cases à cocher, les boutons radio, les zones de texte (ou widgets Entry), les listes avec une barre de défilement verticale (ListBox) et les fenêtres de message. Avant de commencer, examinons certains de ces widgets.

Les cases à cocher servent à faire plusieurs choix parmi plusieurs propositions et ont deux états : cochée ou non cochée, ou on pourrait dire aussi oui ou non. Elles sont généralement utilisées pour fournir une série d'options où une, quelques-unes ou toutes peuvent être sélectionnées. Vous pouvez définir un événement pour vous informer quand la case a changé d'état ou tout simplement pour interroger la valeur du widget à tout moment.

Les boutons radio servent à faire un choix parmi plusieurs propositions. Ils ont aussi deux états, oui ou non. Cependant, ils sont groupés ensembles pour fournir un groupe d'options dont une seule peut être choisie. Vous pouvez avoir plusieurs groupes de boutons radio qui, s'ils sont bien programmés, n'interféreront pas entre eux.

A Listbox provides a list of items for the user to select from. Most times, you want the user to select only one of the items at a time, but there can be occasions that you will allow the user to select multiple items. A scroll bar can be placed either horizontally or vertically to allow the user to easily look through all the items available. Our project will consist of a main window and seven main frames that visually group our widget sets: 1. The first frame will be very basic. It simply consists of various labels, showing the different relief options. 2. The second will contain buttons, again pretty simple, that use the different relief options. 3. In this frame, we'll have two checkboxes and a button that can programmatically toggle them, and they will send their state (1 or 0) back to the terminal window when clicked or toggled. 4. Next, we'll have two groups of three radio buttons, each sending a message to the terminal window when clicked. Each group is separate. 5. This has some text or entry boxes, which aren't new to you, but there's also a button to enable and disable one of them. When disabled, no entry can be made to that textbox. 6. This is a list box with a vertical scroll bar that sends a message to the terminal whenever an item is selected, and will have two buttons. One button will clear the list box and the other will fill it with some dummy values. 7. The final frame will have a series of buttons that will call various types of message boxes.

Une ListBox fournit une liste d'éléments parmi lesquels l'utilisateur peut sélectionner. La plupart du temps, vous voulez que l'utilisateur sélectionne un seul des éléments à la fois, mais, parfois, vous pouvez vouloir permettre à l'utilisateur de sélectionner plusieurs éléments. Une barre de défilement peut être placée horizontalement ou verticalement afin de permettre à l'utilisateur de parcourir facilement tous les éléments disponibles.

Notre projet consistera en une fenêtre principale et sept cadres principaux qui regrouperont visuellement nos ensembles de widgets :

  1. Le premier cadre sera très basique : il contient simplement différents labels, montrant les différentes options de mise en relief.
  2. Le second -plutôt simple également- contiendra des boutons qui utilisent ces mêmes options de relief.
  3. Dans ce cadre, nous aurons deux cases à cocher et un bouton qui inverse leur état par programmation. Elles renverront cet état (1 ou 0) à la fenêtre du terminal lorsqu'elles sont cliquées ou que le bouton est actionné.
  4. Ensuite, nous aurons deux groupes indépendants de trois boutons radio envoyant chacun un message à la fenêtre du terminal lorsqu'on clique dessus.
  5. Celui-ci contient des champs de texte qui ne sont pas nouveaux pour vous, mais il y a aussi un bouton pour activer et désactiver l'un d'eux. Lorsqu'il est désactivé, aucune saisie ne peut y être faite.
  6. Celui-ci contient une liste avec une barre de défilement verticale qui envoie un message au terminal à chaque fois qu'un élément est sélectionné ; il aura deux boutons. Un bouton va effacer la zone de liste et l'autre la remplira avec des valeurs fictives.
  7. Le dernier cadre contient une série de boutons qui appellent les différents types de boîtes de message.

So now, we'll start our project. Let's name it “widgetdemo1.py”. Be sure to save it because we will be writing our project in little pieces, and build on them to make our full app. Each piece revolves around one of the frames. You'll notice that I'm including a number of comments as we go, so you can refer back to what's happening. Here's the first few lines… # widgetdemo1.py # Labels from Tkinter import * class Demo: def init(self,master): self.DefineVars() f = self.BuildWidgets(master) self.PlaceWidgets(f)

Bon, maintenant nous allons commencer notre projet. Nommons-le « widgetdemo1.py ». Assurez-vous de le sauvegarder, car nous allons écrire notre projet par petits morceaux et construire notre application complète petit à petit. Chaque morceau tourne autour de l'un des cadres. Vous remarquerez que j'intègre un certain nombre de commentaires au fur et à mesure, pour que vous puissiez suivre ce qui se passe. Voici les premières lignes…

# widgetdemo1.py # Labels from Tkinter import *

class Demo:

  def __init__(self,principale):
      self.DefinirVariables()
      f = self.ConstruireWidgets(principale)
      self.PlacerWidgets(f)

The first two lines (comments) are the name of the application and what we are concentrating on in this part. Line three is our import statement. Then we define our class. The next line starts our __init__ routine, which you all should be familiar with by now, but, if you are just joining us, it's the code that gets run when we instantiate the routine in the main portion of the program. We are passing it the Toplevel or root window, which comes in as master here. The last three lines (so far), call three different routines. The first (DefineVars) will set up various variables we'll need as we go. The next (BuildWidgets) will be where we define our widgets, and the last (PlaceWidgets) is where we actually place the widgets into the root window. As we did last time, we'll be using the grid geometry manager. Notice that BuildWidgets will return the object “f” (which is our root window), and we'll pass that along to the PlaceWidgets routine.

Les deux premières lignes (commentaires) sont le nom de l'application et le thème de cette partie. La ligne trois est notre déclaration d'importation. Ensuite, nous définissons notre classe. La ligne suivante commence notre routine __init__, avec laquelle vous devriez tous être familiers maintenant ; mais si vous venez juste de nous rejoindre, c'est le code qui est exécuté quand on instancie la routine dans la partie principale du programme. Nous lui passons la fenêtre racine (ou toplevel), qui s'appelle « principale » ici. Les trois dernières lignes (jusqu'à présent) appellent trois routines différentes. La première (DefinirVariables) réglera différentes variables dont nous aurons besoin plus tard. La suivante (ConstruireWidgets) sera l'endroit où nous définissons nos widgets, et la dernière (PlacerWidgets) est celle où nous allons placer les widgets dans la fenêtre racine. Comme nous l'avons fait la dernière fois, nous allons utiliser le gestionnaire de géométrie « grille ». Notez que ConstruireWidgets retournera l'objet « f » (qui est notre fenêtre racine) que nous passerons à la routine PlacerWidgets.

def BuildWidgets(self,master): # Define our widgets frame = Frame(master) # Labels self.lblframe = Frame(frame,relief = SUNKEN,padx = 3, pady = 3, borderwidth = 2, width = 500) self.lbl1 = Label(self.lblframe,text=“Flat Label”,relief = FLAT, width = 13,borderwidth = 2) self.lbl2 = Label(self.lblframe,text=“Sunken Label”, relief = SUNKEN, width = 13, borderwidth = 2) self.lbl3 = Label(self.lblframe,text=“Ridge Label”, relief = RIDGE, width = 13, borderwidth = 2) self.lbl4 = Label(self.lblframe,text=“Raised Label”, relief = RAISED, width = 13, borderwidth = 2) self.lbl5 = Label(self.lblframe,text=“Groove Label”, relief = GROOVE, width = 13, borderwidth = 2) return frame

def ConstruireWidgets(self,principale):
      # definition de nos widgets
      fenetre = Frame(principale)
      # labels (ou etiquettes)
      self.cadreLabels = Frame(fenetre,relief = SUNKEN,padx = 3, pady = 3,
                                 borderwidth = 2, width = 500)
      self.lbl1 = Label(self.cadreLabels,text="Label plat",relief = FLAT,
                                 width = 13,borderwidth = 2)
      self.lbl2 = Label(self.cadreLabels,text="Label creux", relief = SUNKEN,
                                 width = 13, borderwidth = 2)
      self.lbl3 = Label(self.cadreLabels,text="Label arete", relief = RIDGE, width = 13,
                        borderwidth = 2)
      self.lbl4 = Label(self.cadreLabels,text="Label souleve", relief = RAISED,
                        width = 13, borderwidth = 2)
      self.lbl5 = Label(self.cadreLabels,text="Label rainure", relief = GROOVE,
                        width = 13, borderwidth = 2)
      return fenetre

This is our BuildWidgets routine. Each of the lines that start with “self.” have been split for two reasons. First, it's good practice to keep the line length to 80 characters or less. Secondly, it makes it easier on our wonderful editor. You can do two things. One, just make each line long, or keep it as is. Python lets us split lines as long as they are within parentheses or brackets. As I said earlier, we are defining the widgets before we place them in the grid. You'll notice when we do the next routine, that we can also define a widget at the time we place it in the grid, but defining it before we put it in the grid in a routine like this makes it easier to keep track of everything, since we are doing (most of) the definitions in this routine. So, first we define our master frame. This is where we will be putting the rest of our widgets. Next, we define a child (of the master frame) frame that will hold five labels, and call it lblframe. We set the various attributes of the frame here. We set the relief to 'SUNKEN', a padding of 3 pixels on left and right (padx), and 3 pixels on the top and bottom (pady). We also set the borderwidth to 2 pixels so that its sunken relief is noticeable. By default, the borderwidth is set to 0, and the effect of being sunken won't be noticed. Finally, we set the total width of the frame to 500 pixels.

Voici notre routine ConstruireWidgets. Les lignes qui commence par « self. » ont été coupées pour deux raisons. Tout d'abord, c'est une bonne pratique de garder la longueur de la ligne à moins de 80 caractères. Deuxièmement, cela facilite les choses pour notre merveilleux éditeur. Vous avez deux possibilités : soit écrire des lignes longues, soit les garder comme ça. Python nous permet de couper les lignes tant qu'elles sont entre des parenthèses ou des crochets. Comme je l'ai dit précédemment, nous définissons les widgets avant de les placer dans la grille. Quand nous écrirons la routine suivante, vous remarquerez que nous pouvons aussi en définir un au moment où nous le plaçons ; mais le faire dans une routine séparée clarifie les choses, puisque nous y regroupons la plupart des définitions.

Nous définissons donc d'abord notre fenêtre principale. C'est là que nous mettrons le reste de nos widgets. Ensuite, nous définissons une cadre fils (de la fenêtre principale), qui contiendra cinq étiquettes, et l'appelons cadreLabels. Nous réglons les différents attributs du cadre ici. Nous réglons le relief à « en creux » (« SUNKEN »), une marge de 3 pixels à gauche et à droite (padx), et de 3 pixels en haut et en bas (pady). Nous avons également mis la largeur de bordure à 2 pixels de telle sorte que son relief en creux soit perceptible. Par défaut, la largeur de bordure vaut 0 et l'effet de creux ne serait pas visible. Enfin, nous avons mis la largeur totale du cadre à 500 pixels.

Next, we define each label widget that we will use. We set the parent as self.lblframe, and not to frame. This way all the labels are children of lblframe, and lblframe is a child of frame. Notice that each definition is pretty much the same for all five of the labels except the name of the widget (lbl1, lbl2, etc), the text, and the relief or visual effect. Finally, we return the frame back to the calling routine (__init__). Here's our PlaceWidgets routine… def PlaceWidgets(self, master): frame = master # Place the widgets frame.grid(column = 0, row = 0) # Place the labels self.lblframe.grid(column = 0, row = 1, padx = 5, pady = 5, columnspan = 5,sticky='WE') l = Label(self.lblframe,text='Labels |',width=15, anchor='e').grid(column=0,row=0) self.lbl1.grid(column = 1, row = 0, padx = 3, pady = 5) self.lbl2.grid(column = 2, row = 0, padx = 3, pady = 5) self.lbl3.grid(column = 3, row = 0, padx = 3, pady = 5) self.lbl4.grid(column = 4, row = 0, padx = 3, pady = 5) self.lbl5.grid(column = 5, row = 0, padx = 3, pady = 5)

Ensuite, nous définissons chaque widget étiquette que nous allons utiliser. Nous fixons le parent à self.cadreLabels, et non pas fenetre. De cette façon, toutes les étiquettes sont des enfants de cadreLabels qui lui-même est un enfant de fenetre. Remarquez que chaque définition est à peu près semblable pour l'ensemble des cinq étiquettes, sauf le nom du widget (lbl1, lbl2, etc), le texte et le relief ou effet visuel. Enfin, nous retournons la fenêtre à la routine appelante (<nowiki>init</ nowiki>).

Voici notre routine PlacerWidgets…

  def PlacerWidgets(self, principale):
      fenetre = principale
      # place les widgets
      fenetre.grid(column = 0, row = 0)
      # place les labels
      self.cadreLabels.grid(column = 0, row = 1, padx = 5, pady = 5,
                              columnspan = 5,sticky='WE')
      l = Label(self.cadreLabels,text='Labels |',width=15,
                anchor='e').grid(column=0,row=0)
      self.lbl1.grid(column = 1, row = 0, padx = 3, pady = 5)
      self.lbl2.grid(column = 2, row = 0, padx = 3, pady = 5)
      self.lbl3.grid(column = 3, row = 0, padx = 3, pady = 5)
      self.lbl4.grid(column = 4, row = 0, padx = 3, pady = 5)
      self.lbl5.grid(column = 5, row = 0, padx = 3, pady = 5)

We get the frame object in as a parameter called master. We assign that to 'frame' to simply be consistent with what we did in the BuildWidgets routine. Next, we set our main grid up (frame.grid(column = 0, row = 0)). If we don't do this, nothing works correctly. Then we start putting our widgets into the grid locations. First we put the frame (lblframe) that holds all our labels, and set its attributes. We put it in column 0, row 1, set the padding to 5 pixels on all sides, tell it to span 5 columns (left and right), and finally use the “sticky” attribute to force the frame to expand fully to the left and right (“WE”, or West and East). Now comes the part that sort of breaks the rule that I told you about. We are placing a label as the first widget in the frame, but we didn't define it ahead of time. We define it now. We set the parent to lblframe, just like the other labels. We set the text to “Labels |”, the width to 15, and the anchor to east ('e'). If you remember from last time, using the anchor attribute, we can set where in the widget the text will display. In this case, it's along the right border. Now the fun part. Here we define the grid location (and any other grid attributes we need to), simply by appending “.grid” at the end of the label definition. Next, we lay out all of our other labels in the grid - starting at column 1, row 0.

Nous récupérons l'objet fenêtre en tant que paramètre appelé « principale ». Nous l'assignons à « fenetre » simplement pour être cohérent avec ce que nous avons fait dans la routine ConstruireWidgets. Ensuite, nous mettons en place la grille principale (fenetre.grid (column=0, row=0)). Si nous ne faisons pas cela, rien ne fonctionnera correctement. Ensuite, nous commençons à mettre nos widgets dans les emplacements de la grille. D'abord nous mettons le cadre (cadreLabels) qui contient toutes nos étiquettes et définissons ses attributs. Nous le plaçons colonne 0, ligne 1, réglons la marge à 5 pixels sur tous les côtés, lui disons de s'étaler sur 5 colonnes (à droite et à gauche), et enfin utilisons l'attribut « sticky » [Ndt : collant] pour forcer la fenêtre à s'étendre complètement à gauche et à droite (« WE » pour Ouest et Est). Maintenant vient la partie qui casse la règle dont je vous ai parlé. Nous mettons une étiquette comme premier widget dans la fenêtre, mais nous ne l'avons pas défini à l'avance : nous le faisons maintenant. Nous avons mis comme parent cadreLabels, tout comme les autres étiquettes. Nous réglons le texte à « Labels | », la largeur à 15, et l'ancrage à Est ('e'). Si vous vous souvenez de la dernière fois, en utilisant l'attribut d'ancrage, nous pouvons choisir où le texte s'affiche dans le widget. Dans ce cas, c'est le long du bord droit. Maintenant la partie amusante. Ici, nous définissons l'emplacement de la grille (et tous les autres attributs de la grille dont nous avons besoin), simplement en ajoutant « .grid » à la fin de la définition des étiquettes.

Ensuite, nous plaçons toutes nos autres étiquettes dans la grille, à partir de la colonne 1, ligne 0.

Here is our DefineVars routine. Notice that we simply use the pass statement for now. We'll be filling it in later on, and we don't need it for this part: def DefineVars(self): # Define our resources pass And lastly we put in our main routine code: root = Tk() root.geometry('750×40+150+150') root.title(“Widget Demo 1”) demo = Demo(root) root.mainloop()

Voici notre routine DefinirVariables. Notez que nous utilisons simplement l'instruction pass pour l'instant. Nous la remplirons plus tard, car nous n'en avons pas besoin pour cette partie :

  def DefinirVariables(self):
      # definit nos ressources
      pass

Et enfin nous plaçons notre code pour la routine principale :

racine = Tk()
racine.geometry('750x40+150+150')
racine.title("Demo Widget 1")
demo = Demo(racine)

racine.mainloop()

First, we instantiate an instance of Tk. Thern we set the size of the main window to 750 pixels wide by 40 pixels high, and locate it at 150 pixels from the left and top of the screen. Then we set the title of the window and instantiate our Demo object, and finally call the Tk mainloop. Give it a try. You should see the five labels plus the “last minute” label in various glorious effects. Buttons Now save what you have as widgetdemo1a.py, and let's add some buttons. Since we built our base program to be added to, we'll simply add the parts that apply. Let's start with the BuildWidgets routine. After the labels definitions, and before the “return frame” line, add the following…

D'abord, on crée une instance de Tk. Puis nous définissons la taille de la fenêtre principale à 750 pixels de large sur 40 pixels de haut et la localisons à 150 pixels de la gauche et du haut de l'écran. Puis nous réglons le titre de la fenêtre et instancions notre objet Demo et, enfin, appelons la boucle principale de Tk.

Essayez. Vous devriez voir les cinq étiquettes ainsi que l'étiquette de « dernière minute » avec divers effets magnifiques.

Les boutons

Maintenant, enregistrez ce que vous avez en tant que widgetdemo1a.py et nous ajoutons quelques boutons. Puisque nous avons construit notre programme de base ainsi, nous allons simplement pouvoir y ajouter les parties qui manquent. Commençons par la routine ConstruireWidgets. Après les définitions des étiquettes, et avant le « return fenetre », ajoutez ce qui suit…

# Buttons self.btnframe = Frame(frame,relief = SUNKEN,padx = 3, pady = 3, borderwidth = 2, width = 500) self.btn1 = Button(self.btnframe,text=“Flat Button”, relief = FLAT, borderwidth = 2) self.btn2 = Button(self.btnframe,text=“Sunken Button”, relief = SUNKEN, borderwidth = 2) self.btn3 = Button(self.btnframe,text=“Ridge Button”, relief = RIDGE, borderwidth = 2) self.btn4 = Button(self.btnframe,text=“Raised Button”, relief = RAISED, borderwidth = 2) self.btn5 = Button(self.btnframe,text=“Groove Button”, relief = GROOVE, borderwidth = 2) self.btn1.bind('<ButtonRelease-1>',lambda e: self.BtnCallback(1)) self.btn2.bind('<ButtonRelease-1>',lambda e: self.BtnCallback(2)) self.btn3.bind('<ButtonRelease-1>',lambda e: self.BtnCallback(3)) self.btn4.bind('<ButtonRelease-1>',lambda e: self.BtnCallback(4)) self.btn5.bind('<ButtonRelease-1>',lambda e: self.BtnCallback(5))

      # boutons
      self.cadreBoutons = Frame(fenetre,relief = SUNKEN,padx = 3,
                                  pady = 3, borderwidth = 2, width = 500)
      self.btn1 = Button(self.cadreBoutons,text="Bouton plat",
                         relief = FLAT, borderwidth = 2)
      self.btn2 = Button(self.cadreBoutons,text="Bouton creux",
                         relief = SUNKEN, borderwidth = 2)
      self.btn3 = Button(self.cadreBoutons,text="Bouton arete",
                         relief = RIDGE, borderwidth = 2)
      self.btn4 = Button(self.cadreBoutons,text="Bouton souleve",
                         relief = RAISED, borderwidth = 2)
      self.btn5 = Button(self.cadreBoutons,text="Bouton rainure",
                         relief = GROOVE, borderwidth = 2)
      self.btn1.bind('<ButtonRelease-1>',lambda e: self.clicBouton(1))
      self.btn2.bind('<ButtonRelease-1>',lambda e: self.clicBouton(2))
      self.btn3.bind('<ButtonRelease-1>',lambda e: self.clicBouton(3))
      self.btn4.bind('<ButtonRelease-1>',lambda e: self.clicBouton(4))
      self.btn5.bind('<ButtonRelease-1>',lambda e: self.clicBouton(5))

Nothing really new here. We've defined the buttons, with their attributes, and set their callbacks via the .bind configuration. Notice that we are using lambda to send the values 1 through 5 based on which button is clicked. In the callback, we'll use that so we know which button we are dealing with. Now we'll work in the PlaceWidgets routine. Put the following code right after the last label placement: # Place the buttons self.btnframe.grid(column=0, row = 2, padx = 5, pady = 5, columnspan = 5,sticky = 'WE') l = Label(self.btnframe,text='Buttons |',width=15, anchor='e').grid(column=0,row=0) self.btn1.grid(column = 1, row = 0, padx = 3, pady = 3) self.btn2.grid(column = 2, row = 0, padx = 3, pady = 3) self.btn3.grid(column = 3, row = 0, padx = 3, pady = 3) self.btn4.grid(column = 4, row = 0, padx = 3, pady = 3) self.btn5.grid(column = 5, row = 0, padx = 3, pady = 3)

Rien de bien nouveau ici. Nous avons défini les boutons avec leurs attributs et avons fixé leurs fonctions de rappel avec un « .bind ». Notez que nous utilisons lambda pour envoyer les valeurs 1 à 5 suivant le bouton sur lequel on clique. Dans la fonction de rappel, nous allons utiliser cela afin de savoir quel bouton on doit gérer. Maintenant, nous allons travailler dans la routine PlacerWidgets. Placez le code suivant juste après l'emplacement de la dernière étiquette :

      # place les boutons
      self.cadreBoutons.grid(column=0, row = 2, padx = 5,
                               pady = 5, columnspan = 5,sticky = 'WE')
      l = Label(self.cadreBoutons,text='Boutons |',width=15,
                anchor='e').grid(column=0,row=0)
      self.btn1.grid(column = 1, row = 0, padx = 3, pady = 3)
      self.btn2.grid(column = 2, row = 0, padx = 3, pady = 3)
      self.btn3.grid(column = 3, row = 0, padx = 3, pady = 3)
      self.btn4.grid(column = 4, row = 0, padx = 3, pady = 3)
      self.btn5.grid(column = 5, row = 0, padx = 3, pady = 3)     

Once again, nothing really new here, so we'll move on. Here's our callback routine. Put it after the DefineVars routine: def BtnCallback(self,val): if val == 1: print(“Flat Button Clicked…”) elif val == 2: print(“Sunken Button Clicked…”) elif val == 3: print(“Ridge Button Clicked…”) elif val == 4: print(“Raised Button Clicked…”) elif val == 5: print(“Groove Button Clicked…”)

Une fois de plus, rien de vraiment nouveau ici, donc nous allons continuer. Voici notre routine de rappel. Placez-la après la routine DefinirVariables :

  def clicBouton(self,val):
      if val == 1:
          print("Clic bouton plat...")
      elif val == 2:
          print("Clic bouton creux...")
      elif val == 3:
          print("Clic bouton arete...")
      elif val == 4:
          print("Clic bouton souleve...")
      elif val == 5:
          print("Clic bouton rainure...")

Again, nothing really fancy here. We just use a series of IF/ELIF routines to print what button was clicked. The main thing to look at here (when we run the program) is that the sunken button doesn't “move” when you click on it. You would not usually use the sunken relief unless you were making a button that stays “down” when you click it. Finally, we need to tweak the geometry statement to support the extra widgets we put in: root.geometry('750×110+150+150') Ok. All done with this one. Save it and run it. Now save this as widgetdemo1b.py, and we'll move on to checkboxes.

Encore une fois, rien de vraiment sensationnel ici. Nous utilisons simplement une série de routines IF/ELIF pour afficher quel bouton a été cliqué. La principale chose à regarder ici (lorsque nous exécutons le programme) est que le bouton « en creux » ne bouge pas lorsqu'on clique dessus. En général on n'utilise pas le relief « en creux », sauf si vous souhaitez un bouton qui reste enfoncé lorsque vous cliquez dessus. Enfin, nous avons besoin d'ajuster la déclaration de la géométrie à cause des widgets supplémentaires que nous avons ajoutés :

root.geometry ('750x110+150+150')

Ok. C'est terminé pour celui-ci. Enregistrez-le et lancez-le.

Maintenant sauvegardez ceci comme widgetdemo1b.py et nous allons passer aux cases à cocher.

Checkboxes As I said earlier, this part of the demo has a normal button and two checkboxes. The first checkbox is what you would normally expect a checkbox to look like. The second is more like a “sticky” button - when it's not selected (or checked), it looks like a normal button. When you select it, it looks like a button that is stuck down. We can do this by simply setting the indicatoron attribute to False. The “normal” button will toggle the checkboxes from checked to unchecked, and vice versa, each time you click the button. We get to do this programmatically by calling the .toggle method attached to the checkbox. We bind the left mouse button click event (button release) to a function so we can send a message (in this case) to the terminal. In addition to all of this, we are setting two variables (one for each of the checkboxes) that we can query at any time. In this case, each time the checkbox is clicked we query this value and print it. Pay attention to the variable portion of the code. It is used in many widgets.

Les cases à cocher

Comme je l'ai dit précédemment, cette partie de la démo a un bouton normal et deux cases à cocher. L'apparence de la première case est celle à laquelle vous vous attendez normalement. La seconde est plus comme un « bouton collant » - quand elle n'est pas sélectionnée (ou cochée)??, elle ressemble à un bouton normal. Lorsque vous la sélectionnez, elle ressemble à un bouton qui reste enfoncé. Nous pouvons faire cela simplement en définissant l'attribut indicatoron à False. Le bouton « normal » permet de basculer les cases de « cochées » à « décochées » et vice versa, à chaque fois que l'on clique dessus. Nous arrivons à programmer cela en appelant la méthode .toggle liée à la case à cocher. Nous relions l'événement clic gauche de la souris (lorsque le bouton est relâché) à une fonction afin de pouvoir envoyer un message (dans notre cas) au terminal. En plus de tout cela, nous mettons en place deux variables (une pour chacune des cases à cocher) que l'on peut interroger à tout moment. Ici, nous interrogeons ces valeurs et les affichons à chaque fois qu'une case est cliquée. Faites attention à la partie variable du code : elle est utilisée dans de nombreux widgets.

Under the BuildWidget routine, after the button code we just put in and before the return statement, put the following code: # Check Boxes self.cbframe = Frame(frame, relief = SUNKEN, padx = 3, pady = 3, borderwidth = 2, width = 500) self.chk1 = Checkbutton(self.cbframe, text = “Normal Checkbox”, variable=self.Chk1Val) self.chk2 = Checkbutton(self.cbframe, text = “Checkbox”, variable=self.Chk2Val,indicatoron = False) self.chk1.bind('<ButtonRelease-1>',lambda e: self.ChkBoxClick(1)) self.chk2.bind('<ButtonRelease-1>',lambda e: self.ChkBoxClick(2)) self.btnToggleCB = Button(self.cbframe,text=“Toggle Cbs”) self.btnToggleCB.bind('<ButtonRelease-1>',self.btnToggle)

Dans la routine ConstruireWidgets, après le code des boutons que nous venons d'ajouter et avant l'instruction de retour, placez le code suivant :

      # checkbox (ou cases a cocher)
      self.cadreCases = Frame(fenetre, relief = SUNKEN, padx = 3, pady = 3,
                                borderwidth = 2, width = 500)
      self.chk1 = Checkbutton(self.cadreCases, text = "Case a cocher normale",
                              variable=self.Chk1Val)
      self.chk2 = Checkbutton(self.cadreCases, text = "Case a cocher",
                              variable=self.Chk2Val,indicatoron = False)
      self.chk1.bind('<ButtonRelease-1>',lambda e: self.clicCases(1))
      self.chk2.bind('<ButtonRelease-1>',lambda e: self.clicCases(2))
      self.btnInverserCases = Button(self.cadreCases,text="Inverser cases")
      self.btnInverserCases.bind('<ButtonRelease-1>',self.btnInverser)

Again, you have seen all of this before. We create the frame to hold our widgets. We set up a button and two check boxes. Let's place them now: # Place the Checkboxes and toggle button self.cbframe.grid(column = 0, row = 3, padx = 5, pady = 5, columnspan = 5,sticky = 'WE') l = Label(self.cbframe,text='Check Boxes |',width=15, anchor='e').grid(column=0,row=0) self.btnToggleCB.grid(column = 1, row = 0, padx = 3, pady = 3) self.chk1.grid(column = 2, row = 0, padx = 3, pady = 3) self.chk2.grid(column = 3, row = 0, padx = 3, pady = 3)

Encore une fois, vous avez vu tout cela avant. Nous créons le cadre pour contenir nos widgets. Nous créons un bouton et deux cases à cocher. Plaçons-les maintenant :

      # place les cases à cocher et le bouton d'inversion
      self.cadreCases.grid(column = 0, row = 3, padx = 5, pady = 5,
                             columnspan = 5,sticky = 'WE')
      l = Label(self.cadreCases,text='Cases à cocher |',width=15,
                anchor='e').grid(column=0,row=0)
      self.btnInverserCases.grid(column = 1, row = 0, padx = 3, pady = 3)                   
      self.chk1.grid(column = 2, row = 0, padx = 3, pady = 3)
      self.chk2.grid(column = 3, row = 0, padx = 3, pady = 3)

Now we define the two variables that we will use to monitor the value of each check box. Under DefineVars, comment out the pass statement, and add this… self.Chk1Val = IntVar() self.Chk2Val = IntVar() After the button callback return, put the following… def btnToggle(self,p1): self.chk1.toggle() self.chk2.toggle() print(“Check box 1 value is {0}”.format(self.Chk1Val.get())) print(“Check box 2 value is {0}”.format(self.Chk2Val.get())) def ChkBoxClick(self,val): if val == 1: print(“Check box 1 value is {0}”.format(self.Chk1Val.get())) elif val == 2: print(“Check box 2 value is {0}”.format(self.Chk2Val.get()))

Maintenant, nous définissons les deux variables que nous allons utiliser pour surveiller la valeur de chaque case à cocher. Sous DefinirVariables, commentez l'instruction pass et ajouter ceci…

      self.Chk1Val = IntVar ()
      self.Chk2Val = IntVar ()

Après la fonction de rappel des boutons, placez ce qui suit…

  def btnInverser(self,p1):
      self.chk1.toggle()
      self.chk2.toggle()
      print("Valeur de la case à cocher 1 : {0}".format(self.Chk1Val.get()))
      print("Valeur de la case à cocher 2 : {0}".format(self.Chk2Val.get()))        

And finally replace the geometry statement with this… root.geometry('750×170+150+150') Save and run. Save it as widgetdemo1c.py, and let's do radio buttons. Radiobuttons If you are old enough to remember car radios with push buttons to select the station presets, you'll understand why these are called Radiobuttons. When using radiobuttons, the variable attribute is very important. This is what groups the radiobuttons together. In this demo, the first group of buttons is grouped by the variable named self.RBVal. The second is grouped by the variable self.RBValue2. We also need to set the value attribute at design time. This ensures that the buttons will return a value that makes sense whenever they are clicked.

Et enfin remplacez l'instruction de géométrie par ceci…

root.geometry ('750x170+150+150')

Enregistrez et exécutez. Enregistrez-le comme widgetdemo1c.py et continuons avec les boutons radio.

Les boutons radio

Si vous êtes assez vieux pour vous souvenir des autoradios avec boutons poussoirs pour sélectionner les stations préréglées, vous comprendrez pourquoi on appelle cela des boutons radio. Lorsque vous utilisez des boutons radio, l'attribut variable est très important. C'est ce qui regroupe les boutons radio ensemble. Dans cette démo, le premier groupe de boutons est formé avec la variable nommée self.RBVal. Le second groupe est formé par la variable self.RBVal2. Nous devons également définir l'attribut « value » au moment de la conception, afin de garantir que les boutons retourneront une valeur qui a du sens quand ils seront cliqués.

Back to BuildWidgets, and, just before the return statement, add the following code: # Radio Buttons self.rbframe = Frame(frame, relief = SUNKEN, padx = 3, pady = 3, borderwidth = 2, width = 500) self.rb1 = Radiobutton(self.rbframe, text = “Radio 1”, variable = self.RBVal, value = 1) self.rb2 = Radiobutton(self.rbframe, text = “Radio 2”, variable = self.RBVal, value = 2) self.rb3 = Radiobutton(self.rbframe, text = “Radio 3”, variable = self.RBVal, value = 3) self.rb1.bind('<ButtonRelease-1>',lambda e: self.RBClick()) self.rb2.bind('<ButtonRelease-1>',lambda e: self.RBClick()) self.rb3.bind('<ButtonRelease-1>',lambda e: self.RBClick()) self.rb4 = Radiobutton(self.rbframe, text = “Radio 4”, variable = self.RBVal2, value = “1-1”) self.rb5 = Radiobutton(self.rbframe, text = “Radio 5”, variable = self.RBVal2, value = “1-2”) self.rb6 = Radiobutton(self.rbframe, text = “Radio 6”, variable = self.RBVal2, value = “1-3”) self.rb4.bind('<ButtonRelease-1>',lambda e: self.RBClick2()) self.rb5.bind('<ButtonRelease-1>',lambda e: self.RBClick2()) self.rb6.bind('<ButtonRelease-1>',lambda e: self.RBClick2())

Retournez dans ConstruireWidgets, et ajoutez le code suivant juste avant l'instruction de retour :

      # boutons radio
      self.cadreBoutonsRadio = Frame(fenetre, relief = SUNKEN, padx = 3, pady = 3, borderwidth = 2, width = 500)
      self.rb1 = Radiobutton(self.cadreBoutonsRadio, text = "Radio 1", variable = self.RBVal, value = 1)
      self.rb2 = Radiobutton(self.cadreBoutonsRadio, text = "Radio 2", variable = self.RBVal, value = 2)
      self.rb3 = Radiobutton(self.cadreBoutonsRadio, text = "Radio 3", variable = self.RBVal, value = 3)
      self.rb1.bind('<ButtonRelease-1>',lambda e: self.clicBoutonRadio())
      self.rb2.bind('<ButtonRelease-1>',lambda e: self.clicBoutonRadio())
      self.rb3.bind('<ButtonRelease-1>',lambda e: self.clicBoutonRadio())
      self.rb4 = Radiobutton(self.cadreBoutonsRadio, text = "Radio 4", variable = self.RBVal2, value = "1-1")
      self.rb5 = Radiobutton(self.cadreBoutonsRadio, text = "Radio 5", variable = self.RBVal2, value = "1-2")
      self.rb6 = Radiobutton(self.cadreBoutonsRadio, text = "Radio 6", variable = self.RBVal2, value = "1-3")
      self.rb4.bind('<ButtonRelease-1>',lambda e: self.clicBoutonRadio2())
      self.rb5.bind('<ButtonRelease-1>',lambda e: self.clicBoutonRadio2())
      self.rb6.bind('<ButtonRelease-1>',lambda e: self.clicBoutonRadio2())                            

In PlaceWidgets, add this: # Place the Radio Buttons and select the first one self.rbframe.grid(column = 0, row = 4, padx = 5, pady = 5, columnspan = 5,sticky = 'WE') l = Label(self.rbframe, text='Radio Buttons |', width=15,anchor='e').grid(column=0,row=0) self.rb1.grid(column = 2, row = 0, padx = 3, pady = 3, sticky = 'EW') self.rb2.grid(column = 3, row = 0, padx = 3, pady = 3, sticky = 'WE') self.rb3.grid(column = 4, row = 0, padx = 3, pady = 3, sticky = 'WE') self.RBVal.set(“1”) l = Label(self.rbframe,text='| Another Set |', width = 15, anchor = 'e').grid(column = 5, row = 0) self.rb4.grid(column = 6, row = 0) self.rb5.grid(column = 7, row = 0) self.rb6.grid(column = 8, row = 0) self.RBVal2.set(“1-1”)

Ajoutez ceci dans PlacerWidgets :

      # place les boutons radio et selectionne le premier
      self.cadreBoutonsRadio.grid(column = 0, row = 4, padx = 5, pady = 5, columnspan = 5,sticky = 'WE')
      l = Label(self.cadreBoutonsRadio,
                text='Boutons radio |',
                width=15,anchor='e').grid(column=0,row=0)
      self.rb1.grid(column = 2, row = 0, padx = 3, pady = 3, sticky = 'EW')
      self.rb2.grid(column = 3, row = 0, padx = 3, pady = 3, sticky = 'WE')
      self.rb3.grid(column = 4, row = 0, padx = 3, pady = 3, sticky = 'WE')
      self.RBVal.set("1")        
      l = Label(self.cadreBoutonsRadio,text='| Un autre groupe |',
                width = 15,
                anchor = 'e').grid(column = 5, row = 0)
      self.rb4.grid(column = 6, row = 0)
      self.rb5.grid(column = 7, row = 0)
      self.rb6.grid(column = 8, row = 0)
      self.RBVal2.set("1-1")             

One thing of note here. Notice the “last minute” label definitions in the PlaceWidget routine. These long lines are broken up to show how to use parens to allow our long lines to be formatted nicely in our code, and still function correctly. In DefineVars add: self.RBVal = IntVar() Add the click routines: def RBClick(self): print(“Radio Button clicked - Value is {0}”.format(self.RBVal.get())) def RBClick2(self): print(“Radio Button clicked - Value is {0}”.format(self.RBVal2.get())) and, finally, rework the geometry statement as follows. root.geometry('750×220+150+150')

Une chose à noter ici. Remarquez les définitions de « dernière minute » pour les étiquettes dans la routine PlacerWidgets. Ces lignes longues sont coupées pour montrer comment utiliser les parenthèses pour permettre à nos longues lignes d'être formatées correctement dans notre code, et de fonctionner toujours correctement.

Dans DefinirVariables, ajoutez :

      self.RBVal = IntVar ()

Ajoutez les routines de clics :

  def clicBoutonRadio(self):
      print("Clic bouton radio - Valeur : {0}".format(self.RBVal.get()))        
  def clicBoutonRadio2(self):
      print("Clic bouton radio - Valeur : {0}".format(self.RBVal2.get()))             

et enfin modifiez à nouveau la géométrie comme ceci.

root.geometry ('750x220+150+150')

Save the project as widgetdemo1d.py, and run it. Now, we'll start working on standard textboxes (or entry widgets). Entry Again, we've used textboxes or entry widgets in various GUI flavors before. However this time, as I said earlier, we will show how to keep the user from making changes to the textbox by disabling it. This is helpful if you are showing some data, and allowing the user to change it only when in the “edit” mode. By now, you should be pretty sure that the first thing we need to do is add code to the BuildWidget routine: # Textboxes self.tbframe = Frame(frame, relief = SUNKEN, padx = 3, pady = 3, borderwidth = 2, width = 500) self.txt1 = Entry(self.tbframe, width = 10) self.txt2 = Entry(self.tbframe, disabledbackground=“#cccccc”, width = 10) self.btnDisable = Button(self.tbframe, text = “Enable/Disable”) self.btnDisable.bind('<ButtonRelease-1>', self.btnDisableClick)

Enregistrez le projet sous widgetdemo1d.py et exécutez-le. Maintenant, nous allons travailler sur les champs de texte standard (ou widgets de saisie).

Les champs de texte

Encore une fois, nous avons déjà utilisé des champs de texte (ou widgets de saisie) dans diverses interfaces graphiques auparavant. Mais cette fois-ci, comme je l'ai dit précédemment, nous allons montrer comment empêcher l'utilisateur de faire des changements dans le champ texte en le désactivant. Cela s'avère utile si vous affichez certaines données et ne permettez à l'utilisateur de les modifier que lorsqu'il est dans le mode édition. À présent, vous devriez savoir que la première chose que nous devons faire est d'ajouter du code à la routine ConstruireWidgets :

      # champs de texte
      self.cadreChampsTexte = Frame(fenetre, relief = SUNKEN, padx = 3, pady = 3, borderwidth = 2, width = 500)
      self.txt1 = Entry(self.cadreChampsTexte, width = 10)
      self.txt2 = Entry(self.cadreChampsTexte, disabledbackground="#cccccc", width = 10)
      self.btnDesactiver = Button(self.cadreChampsTexte, text = "Activer/Desactiver")
      self.btnDesactiver.bind('<ButtonRelease-1>', self.clicBoutonDesactiver)

Next, add this code to the PlaceWidget routine: # Place the Textboxes self.tbframe.grid(column = 0, row = 5, padx = 5, pady = 5, columnspan = 5,sticky = 'WE') l = Label(self.tbframe,text='Textboxes |',width=15, anchor='e').grid(column=0,row=0) self.txt1.grid(column = 2, row = 0, padx = 3, pady = 3) self.txt2.grid(column = 3, row = 0, padx = 3, pady = 3) self.btnDisable.grid(column = 1, row = 0, padx = 3, pady = 3) Add this line to the bottom of the DefineVars routine: self.Disabled = False

Ensuite, ajoutez le code à la routine PlacerWidgets :

      # place les champs de texte
      self.cadreChampsTexte.grid(column = 0, row = 5, padx = 5, pady = 5, columnspan = 5,sticky = 'WE')
      l = Label(self.cadreChampsTexte,text='Champs de texte |',width=15, anchor='e').grid(column=0,row=0)
      self.txt1.grid(column = 2, row = 0, padx = 3, pady = 3)
      self.txt2.grid(column = 3, row = 0, padx = 3, pady = 3)
      self.btnDesactiver.grid(column = 1, row = 0, padx = 3, pady = 3)

Ajoutez cette ligne en bas de la routine DefinirVariables :

    self.Disabled = False

Now, add the function that responds to the button click event: def btnDisableClick(self,p1): if self.Disabled == False: self.Disabled = True self.txt2.configure(state='disabled') else: self.Disabled = False self.txt2.configure(state='normal') And finally, rework the geometry statement: root.geometry('750×270+150+150')

Maintenant ajoutez la fonction qui répond au clic sur le bouton :

  def clicBoutonDesactiver(self,p1):
      if self.Disabled == False:
          self.Disabled = True
          self.txt2.configure(state='disabled')
      else:
          self.Disabled = False
          self.txt2.configure(state='normal')

Reconfigurer les dimensions à : root.geometry('750×270+150+150')

Save it as widgetdemo1d.py, and run it. Listbox Next we'll work our listbox. Starting in BuildWidgets, add the following code: # List Box Stuff self.lstframe = Frame(frame, relief = SUNKEN, padx = 3, pady = 3, borderwidth = 2, width = 500 ) # Scrollbar for list box self.VScroll = Scrollbar(self.lstframe) self.lbox = Listbox(self.lstframe, height = 5, yscrollcommand = self.VScroll.set)

Sauvegardez-le sous le nom widgetdemo1d.py et exécutez-le.

Les listes

Ensuite nous allons travailler sur les listes. En commençant dans ConstruireWidgets, ajoutez le code suivant :

      # Données pour la liste
      self.cadreListe = Frame(fenetre,
                                relief = SUNKEN,
                                padx = 3, 
                                pady = 3, 
                                borderwidth = 2, 
                                width = 500
      )
      # boite avec barre de défilement pour la liste
      self.defilementV = Scrollbar(self.cadreListe)
      self.liste = Listbox(self.cadreListe, 
                           height = 5,
                           yscrollcommand = self.defilementV.set)

# default height is 10 self.lbox.bind('«ListboxSelect»',self.LBoxSelect) self.VScroll.config(command = self.lbox.yview) self.btnClearLBox = Button( self.lstframe, text = “Clear List”, command = self.ClearList, width = 11 ) self.btnFillLBox = Button( self.lstframe, text = “Fill List”, command = self.FillList, width = 11 ) # «ListboxSelect» is virtual event # Fill the list box self.FillList()

      # hauteur par defaut = 10
      self.liste.bind('<<ListboxSelect>>',self.listeSelection)
      self.defilementV.config(command = self.liste.yview)
      self.btnEffacerListe = Button(
           self.cadreListe,
           text = "Effacer liste",
           command = self.effacerListe,
           width = 11
      )
      self.btnRemplirListe = Button(
           self.cadreListe,
           text = "Remplir liste",
           command = self.remplirListe, 
           width = 11
      )
      # <<ListboxSelect>> est un evenement virtuel
      # remplit la liste
      self.remplirListe()

As usual, we create our frame. Then we create our vertical scroll bar. We do this before we create the list box, because we have to reference the scrollbar '.set' method. Notice the attribute 'height = 5'. This forces the listbox to show 5 items at a time. In the .bind statement, we use '«ListboxSelect»' as the event. It's called a virtual event, since it's not really an “official” event. Now, we'll deal with the additional code for the PlaceWidgets routine: # Place the Listbox and support buttons self.lstframe.grid(column = 0, row = 6, padx = 5, pady = 5, columnspan = 5,sticky = 'WE') l = Label(self.lstframe,text='List Box |',width=15, anchor='e').grid(column=0,row=0,rowspan=2) self.lbox.grid(column = 2, row = 0,rowspan=2) self.VScroll.grid(column = 3, row = 0,rowspan = 2, sticky = 'NSW') self.btnClearLBox.grid(column = 1, row = 0, padx = 5) self.btnFillLBox.grid(column = 1, row = 1, padx = 5)

Comme d'habitude, nous créons notre cadre. Puis nous créons notre barre de défilement verticale. Nous le faisons avant de créer la liste parce que nous devons faire référence à la méthode « .set » de la barre de défilement. Remarquez l'attribut « height = 5 ». Cela force la liste à montrer 5 éléments à la fois. Dans la déclaration .bind, nous utilisons « «ListboxSelect» » comme événement. C'est ce qu'on appelle un événement virtuel, puisque ce n'est pas vraiment un événement « officiel ».

Maintenant, nous allons nous occuper du code supplémentaire dans la routine PlacerWidgets :

      # place la liste et les boutons associes
      self.cadreListe.grid(column = 0, row = 6, padx = 5, pady = 5, columnspan = 5,sticky = 'WE')
      l = Label(self.cadreListe,text='Liste |',width=15, anchor='e').grid(column=0,row=0,rowspan=2)
      self.liste.grid(column = 2, row = 0,rowspan=2)
      self.defilementV.grid(column = 3, row = 0,rowspan = 2, sticky = 'NSW')
      self.btnEffacerListe.grid(column = 1, row = 0, padx = 5)
      self.btnRemplirListe.grid(column = 1, row = 1, padx = 5)        

In DefineVars add this… # List for List box items self.examples = ['Item One','Item Two','Item Three','Item Four'] And add the following support routines: def ClearList(self): self.lbox.delete(0,END) def FillList(self): # Note, clear the listbox first…no check is done for ex in self.examples: self.lbox.insert(END,ex) # insert([0,ACTIVE,END],item)

Ajoutez ceci dans DefinirVariables :

      # les elements pour notre liste 
      self.exemples = ['Element un','Element deux','Element trois','Element quatre']        

Et ajoutez les routines de support suivantes :

  def effacerListe(self):
      self.liste.delete(0,END)
      
  def remplirListe(self):
      # Note : effacer d'abord la liste ; aucune verification n'est faite
      for ex in self.exemples:
          self.liste.insert(END,ex)   
      # insert([0,ACTIVE,END],element)

def LBoxSelect(self,p1): print(“Listbox Item clicked”) items = self.lbox.curselection() selitem = items[0] print(“Index of selected item = {0}”.format(selitem)) print(“Text of selected item = {0}”.format(self.lbox.get(selitem))) Finally, update the geometry line. root.geometry('750×370+150+150')

  def listeSelection(self,p1):
      print("Clic sur un élément de la liste")
      items = self.liste.curselection()
      selitem = items[0]
      print("Index de l'élément choisi : {0}".format(selitem))
      print("Texte de l'élément choisi : {0}".format(self.liste.get(selitem)))

Enfin, mettez à jour la ligne de géométrie :

root.geometry('750x370+150+150')

Save this as widgetdemo1e.py, and run it. Now we will do our last modifications to our application. Message Dialogs This section is simply a series of “normal” buttons that will call various types of Message Dialogs. We've done them before in a different GUI toolkit. We will explore only 5 different types, but there are more. In this section, we'll look at Info, Warning, Error, Question, and Yes/No dialogs. These are very useful when you need to pass some information to your user in a rather big way. In the BuildWidgets routine add… # Buttons to show message boxes and dialogs self.mbframe = Frame(frame,relief = SUNKEN,padx = 3, pady = 3, borderwidth = 2) self.btnMBInfo = Button(self.mbframe,text = “Info”) self.btnMBWarning = Button(self.mbframe,text = “Warning”) self.btnMBError = Button(self.mbframe,text = “Error”) self.btnMBQuestion = Button(self.mbframe,text = “Question”) self.btnMBYesNo = Button(self.mbframe,text = “Yes/No”) self.btnMBInfo.bind('<ButtonRelease-1>', lambda e: self.ShowMessageBox(1)) self.btnMBWarning.bind('<ButtonRelease-1>', lambda e: self.ShowMessageBox(2)) self.btnMBError.bind('<ButtonRelease-1>', lambda e: self.ShowMessageBox(3)) self.btnMBQuestion.bind('<ButtonRelease-1>', lambda e: self.ShowMessageBox(4)) self.btnMBYesNo.bind('<ButtonRelease-1>', lambda e: self.ShowMessageBox(5))

Sauvegarder cela comme widgetdemo1e.py et exécutez-le. Maintenant, nous allons faire les dernières modifications à notre application.

Les boîtes de dialogue

Cette section est tout simplement une série de boutons « normaux » qui appellent les différents types de boîtes de dialogue. Nous les avons déjà rencontrés avec une boîte à outils différente. Nous allons explorer seulement 5 types différents, mais il y en a plus. Dans cette section, nous allons regarder Information, Avertissement, Erreur, Question, et Dialogue Oui/Non. Ils sont très utiles lorsque vous avez besoin de faire passer des informations à votre utilisateur d'une manière assez forte. Dans la routine ConstruireWidgets, ajoutez…

      # boutons pour afficher les fenetres de messages et de dialogues
      self.cadreMessages = Frame(fenetre,relief = SUNKEN,padx = 3, pady = 3, borderwidth = 2)
      self.btnMBInfo = Button(self.cadreMessages,text = "Info")
      self.btnMBWarning = Button(self.cadreMessages,text = "Avertissement")
      self.btnMBError = Button(self.cadreMessages,text = "Erreur")
      self.btnMBQuestion = Button(self.cadreMessages,text = "Question")
      self.btnMBYesNo = Button(self.cadreMessages,text = "Oui/Non")
      self.btnMBInfo.bind('<ButtonRelease-1>', lambda e: self.afficheFenetreMessage(1))
      self.btnMBWarning.bind('<ButtonRelease-1>', lambda e: self.afficheFenetreMessage(2))
      self.btnMBError.bind('<ButtonRelease-1>', lambda e: self.afficheFenetreMessage(3))
      self.btnMBQuestion.bind('<ButtonRelease-1>', lambda e: self.afficheFenetreMessage(4))
      self.btnMBYesNo.bind('<ButtonRelease-1>', lambda e: self.afficheFenetreMessage(5))

Now, add the code for the PlaceWidgets routine: # Messagebox buttons and frame self.mbframe.grid(column = 0,row = 7, columnspan = 5, padx = 5, sticky = 'WE') l = Label(self.mbframe,text='Message Boxes |',width=15, anchor='e').grid(column=0,row=0) self.btnMBInfo.grid(column = 1, row = 0, padx= 3) self.btnMBWarning.grid(column = 2, row = 0, padx= 3) self.btnMBError.grid(column = 3, row = 0, padx= 3) self.btnMBQuestion.grid(column = 4, row = 0, padx= 3) self.btnMBYesNo.grid(column = 5, row = 0, padx= 3)

Maintenant ajoutez le code dans la routine PlacerWidgets :

      # boutons de boîtes de messages et cadre
      self.cadreMessages.grid(column = 0,row = 7, columnspan = 5, padx = 5, sticky = 'WE')
      l = Label(self.cadreMessages,text='Messages |',width=15, anchor='e').grid(column=0,row=0)
      self.btnMBInfo.grid(column = 1, row = 0, padx= 3)
      self.btnMBWarning.grid(column = 2, row = 0, padx= 3)
      self.btnMBError.grid(column = 3, row = 0, padx= 3)
      self.btnMBQuestion.grid(column = 4, row = 0, padx= 3)
      self.btnMBYesNo.grid(column = 5, row = 0, padx= 3)

Here is the support routine. For the first three (Info, Warning, and Error), you simply call 'tkMessageBox.showinfo', or whichever you need, with two parameters. First is the title for the message dialog, and second is the actual message you want to show. The icon is handled for you by tkinter. For the dialogs that provide a response (question, yes/no), we provide a variable that receives the value of which button was clicked. In the case of the question dialog, the response is either “yes” or “no”, and, in the case of the yes/no dialog, the response is either “True” or “False”. def ShowMessageBox(self,which): if which == 1: tkMessageBox.showinfo('Demo','This is an INFO messagebox') elif which == 2: tkMessageBox.showwarning('Demo','This is a WARNING messagebox') elif which == 3: tkMessageBox.showerror('Demo','This is an ERROR messagebox') elif which == 4: resp = tkMessageBox.askquestion('Demo','This is a QUESTION messagebox?') print('{0} was pressed…'.format(resp)) elif which == 5: resp = tkMessageBox.askyesno('Demo','This is a YES/NO messagebox') print('{0} was pressed…'.format(resp))

Voici la routine d'appui. Pour les trois premiers (Info, Avertissement et Erreur), il suffit d'appeler « tkMessageBox.showinfo », ou celui dont vous avez besoin, avec deux paramètres. Le premier est le titre de la boîte de message et le second est le message réel que vous voulez montrer. L'icône est gérée pour vous par Tkinter. Pour les dialogues qui fournissent une réponse (Question, Oui/Non), nous fournissons une variable qui reçoit la valeur correspondant au bouton cliqué. Dans le cas de la boîte de dialogue Question, la réponse est « Oui » ou « Non », et dans le cas du dialogue Oui/Non, la réponse est « True » ou « False ».

  def afficheFenetreMessage(self,which):
      if which == 1:
          tkMessageBox.showinfo('Demo','Voici un message INFO')
      elif which == 2:
          tkMessageBox.showwarning('Demo','Voici un message WARNING (avertissement)')
      elif which == 3:
          tkMessageBox.showerror('Demo','Voici un message ERREUR')
      elif which == 4:
          rep = tkMessageBox.askquestion('Demo','Voici une QUESTION ?')
          print('clic sur {0}...'.format(rep))
      elif which == 5:
          rep = tkMessageBox.askyesno('Demo','Voici un message OUI/NON')
          print('clic sur {0}...'.format(rep))

Finally, modify the geometry line: root.geometry('750×490+550+150') Save this as widgetdemo1f.py, and play away. I've put the code for widgetdemo1f.py on pastebin at http://pastebin.com/ZqrgHcdG. That's it for this time. I hope this has inspired you to explore all of the goodies that tkinter provides. See you next time.

Enfin, modifiez la ligne de géométrie :

root.geometry('750x490+550+150')

Sauvegardez ceci sous le nom widgetdemo1f.py et amusez-vous avec.

J'ai placé le code de widgetdemo1f.py sur pastebin ici : http://pastebin.com/TQgppVnF

C'est tout pour cette fois. J'espère que ceci vous aura inspiré à explorer toutes les fonctionnalités proposées par tkinter. À la prochaine fois.

issue52/tutopython.txt · Dernière modification : 2011/11/02 15:29 de marchois