Outils pour utilisateurs

Outils du site


issue149:python

Ceci est une ancienne révision du document !


Occasionally, I help Don Rozenberg, the creator of Page (a GUI designer for Python) with testing, demos, tutorials and support. This week, we had a user who was asking about an issue with the ttk themed widgets. Don passed the question down to me and I had to scramble since it’s been a long time since I’ve used the ttk specific widgets.

If you are unfamiliar with ttk widgets, it is an additional set of widgets available for Tkinter from the Tk toolkit, which is part of Tcl. The Tk toolkit is available for Perl and Ruby as well as Tcl and Python. The ttk portion of the toolkit gives alternate widgets for many of the standard Tk widgets…

They pretty much act as the standard widgets do, they just have a different, more updated look to them (at least to some people). There are also preset styles that you can use that changes the look of them. On Linux machines, there are 4 pre-defined styles, named clam, alt, default and classic). On Windows machines, there are three others as well, called “winnative’, ‘vista’ and ‘xpnative’. And Mac users have other choices, but the bottom line there are on all platforms, the 4 base styles that are on Linux.

When I am making a UI, I usually shy away from the ttk widgets for the most part because they have less “visible” attributes than the standard widgets and I feel like I lose some control over my program. Here is an example using Page’s attribute editor…

I know this graphic is mostly unreadable, but it is illustrative of the number of attributes that you can control for a standard button (on the left side) compared to the ttk button (on the right). Part of the discrepancy stems from the fact that the style controls most of the attributes that seem to be missing. In a good way, this is a good thing. On the other hand, since the style is “taking care of these attributes for you”, for the most part the style keeps you from making changes to what could normally be an important attribute when you are trying to “push the envelope” and make your GUI program look more modern than standard Tkinter widgets allow.

While the above might dissuade many users from even trying ttk widgets, a larger number of users are overwhelmed by how hard it is to find really good documentation on the use and customization of ttk widgets. Even those sites on the Internet that touch on how to do it, only give a small amount of information and even then, there isn’t much about using ttk goodies in Page. So, I thought I’d try to fix this in some small way.

One of the problems with using ttk widgets in Page is that Page has (at least currently) no way to set which of the styles you want to use either when you are designing your GUI and to make it work when you try to run your program shows the ‘default’ style at least under Linux. I believe that Windows users have the ‘winnative’ style as the default. While it is easy to change/setup the style in the startup function ( def init() ), a casual user who’s done no serious research on the subject would look at the results and say “We’ll, that doesn’t look like what I wanted!” and go back to using the standard widgets. Moreover, there could be issues when doing cross platform GUI design. Since Linux doesn’t support the ‘winnative’ style, there could be issues at best (the program uses the default style) and at worst, simply throws error messages that, again, for those who haven’t spent a fair amount of time researching would be meaningless.

So we’ll try to get a handle on some of the issues and get the hard stuff out of the way in this article. The latest version of Page is 4.25.1 and you can get the latest at https://sourceforge.net/ projects/page/ . Once you have it installed, get it fired up and we’ll throw together a quick demo.

Start by making your new form about 516 pixels wide by 450 high. Now set the title to something like “ttk Widget Demo”.

Next, add a TButton widget to act as our Exit button. Put it in the upper right corner of the form. Set the command attribute to “on_btnExit” and change the text attribute to “Exit”.

Now, place a TLabel frame below the Exit button and size it to about 150 by 285. This will hold 7 TRadiobuttons. Set the Text attribute to “Styles”. Next add 7 TRadiobuttons into the TLabelframe. They should be aliased to “TRadiobutton1” to “TRadiobutton7”. This is important because we will reference them directly when the program runs. For each of the buttons, you need to set a few attributes. In the command attribute box, enter “on_rbClick”. It is important that each TRadiobutton references the same callback. Then set the value attribute to the count of that widget minus 1. So, for example, for TRadiobutton1, the value would be 0, TRadiobutton2 would be 1, TRadiobutton3 would be 2 and so on. Finally, for the TRadiobuttons, simply make sure that the Variable attribute reads “::selectedButton”, again the same for all 7. I used a vertical separation of 30 pixels between each one and lined them all with an X position of 20.

We are over half way done. Now you need to put a TCheckbutton, a TCombobox, a TProgressbar and a TEntry widget in the form on the left side of the form. You can space it anyway you want. Finally, if you want, you can add a vertical and horizontal TSeparator for some decoration. You can see what my final form looks like in the image at the top of this article.

Save the Page file as “ttkdemo.tcl”, then generate both of the Python modules. They will be saved as “ttkdemo.py” and “ttkdemo_support.py” automatically by Page. You can close Page now.

Now for the code. In your favorite text editor or IDE, open the “ttkdemo_support.py” file. That's where all of our code will be entered.

If everything went correctly during the GUI design process, Page should have created the following functions for you…

set_Tk_var() on_rbClick() on_btnExit() init() destroy_window() and the if name routine.

Our code will be pretty minimal. We'll start with fleshing out the on_rbClick() function. This is a callback function that fires whenever the user clicks on one of the TRadiobuttons. Code is shown on the next page, top right.

Page put the first two statements (print(…) and sys.stdout.flush() in for you. So the first line of our code prints the value of the TRadiobutton that we entered in the 'value' attribute of the widget when we were designing the form in Page. This way the program knows which button was clicked on. The next line gets the styles that ttk supports for this operating system. In Linux, there will be 4 items and on Windows there will be 7 and they will be returned as a tuple, like this…

('clam', 'alt', 'default', 'classic')

Next we repeat the operation in the print statement that gets the value of that TRadiobutton and finally, we tell ttk to use the correct style to draw the widgets. This happens immediately.

Now we'll put in the code for the on_btnExit() callback…

def on_btnExit():

      print('ttkdemo_support.on_btnExit')
  

sys.stdout.flush()

destroy_window()

We'll add just one line to the bottom of the init function, which if you remember, is the very last thing that gets run before the form is shown to the user and the program actually starts. This will call the routine that will do all of our setup on the form.

setup_styles()

This is the longest and some would say the most complicated function in the program. It is also the only one that we have to create fully by hand. I'll break up the function in parts (see above).

So first, we have the function definition and we create a list that consists of the 7 TRadiobuttons that we entered. We use their names directly and preface each with a “w.”. By doing this, we can reference any of the 7 widgets directly.

  s = ttk.Style()
  cntr = 0

The next two lines, create an object named “s” that holds all of the style information from ttk. We'll only be using one part of it, but once you get more familiar with ttk, this gives you access to many things. We also create and initialize a counter variable.

  def clear_radio_buttons():
      

for i in range(7):

          rblist[i].configure(text='')
          rblist[i].configure(state='disabled')

Now we create a function within our function that clears the text field and disables all 7 of the radio buttons. I'm sure you realize why we clear the text fields, and the reason we disable all the TRadiobutton widgets at this point is so that if we are running under Linux, the user can't click buttons 5 through 7, but if we are under Windows, all 7 will be activated in the next bit of code. Welcome to cross-platform programming!

  clear_radio_buttons()

Now we call our in-function function that sets up the TRadiobuttons and we are ready to “load” them all up.

  for i in s.theme_names():
      rblist[cntr].configure(text=i)
      rblist[cntr].configure(state='normal')
      cntr += 1

We'll use a simple for loop to do this. We will again, use the list that we created of all the TRadiobutton widgets to get the actual widget object name, set it's text to the style name for that position in the loop and set the state back to “normal”.

Finally, we'll set the TProgress bar so it does something. The progress bar has two modes, 'determinate' for when you know how far into a process you are and you want to show a percentage of that progress. The 'indeterminate' mode simply causes a bar to move back and forth to show something is happening. You use the ‘.start()’ method to begin the motion and the ‘.stop()’ method to stop it. We'll use the 'indeterminate' method just for fun.

  w.TProgressbar1.config(mode='indeterminate')
  

w.TProgressbar1.start()

That's it. Save your program and you can run it in Python. Now, anytime you want to use ttk widgets in your GUI, you know what they will look like under any style and once you have selected one to your liking, you can put somewhere in the init() function (after the first four lines) the following lines…

style = ttk.Style()

  style.theme_use(‘your_style_here’)

That was easy and pretty much painless. As always, I've put all the code up on pastebin at the following links…

ttkdemo.tcl - https://pastebin.com/yFnH6QXF

ttkdemo.py - https://pastebin.com/BWV1CxWN

ttkdemo_support.py - https://pastebin.com/N72NXsUC

When you download them, they will most likely come down as “ttkdemo.tcl.txt”, “ttkdemo.py.txt” and so on. That’s just a pastebin thing. Simply delete the “.txt” from the files and you’re good to go.

Until next time, have a great month and keep programming!

issue149/python.1569912781.txt.gz · Dernière modification : 2019/10/01 08:53 de d52fr