Outils pour utilisateurs

Outils du site


issue52:tutopython

Ceci est une ancienne révision du document !


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 parlerai 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 messages. 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, et quelques-unes, plusieurs ou toutes ces options peuvent être sélectionnées. Vous pouvez définir un événement pour vous informer quand la case a été cochée ou décochée, 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 ensemble 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 l'un avec l'autre.

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 il peut y avoir des occasions où vous permettrez à l'utilisateur de sélectionner plusieurs éléments. Une barre de défilement peut être placé 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 relief.
  2. Le second contiendra des boutons, c'est plutôt simple aussi, qui utilisent différentes options de relief.
  3. Dans ce cadre, nous aurons deux cases à cocher et un bouton qui peut les activer/désactiver, et qui enverront leur état (1 ou 0) à la fenêtre du terminal lorsqu'on clique dessus ou les active/désactive.
  4. Ensuite, nous aurons deux groupes de trois boutons radio, chacun envoyant un message à la fenêtre du terminal lorsqu'on clique dessus. Chaque groupe est indépendant de l'autre.
  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 est une liste avec une barre de défilement verticale qui envoie un message au terminal à chaque fois qu'un élément est sélectionné, et 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)

Alors 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 ce sur quoi nous nous concentrons sur 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) appelent 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), et que nous le 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.fenetreLabels = Frame(fenetre,relief = SUNKEN,padx = 3, pady = 3,
                                 borderwidth = 2, width = 500)
      self.lbl1 = Label(self.fenetreLabels,text="Label plat",relief = FLAT,
                                 width = 13,borderwidth = 2)
      self.lbl2 = Label(self.fenetreLabels,text="Label creux", relief = SUNKEN,
                                 width = 13, borderwidth = 2)
      self.lbl3 = Label(self.fenetreLabels,text="Label arete", relief = RIDGE, width = 13,
                        borderwidth = 2)
      self.lbl4 = Label(self.fenetreLabels,text="Label souleve", relief = RAISED,
                        width = 13, borderwidth = 2)
      self.lbl5 = Label(self.fenetreLabels,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.

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)

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.

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()

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…

# 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))

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)

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…”)

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.

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.

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)

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)

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()))

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.

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())

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”)

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')

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)

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

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')

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)

# 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()

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)

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)

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')

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))

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)

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))

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.

version française : http://pastebin.com/TQgppVnF

issue52/tutopython.1316373323.txt.gz · Dernière modification : 2011/09/18 21:15 de fredphil91