Ceci est une ancienne révision du document !
During the creation of PAGE 7.4, I had created a widget demo that included almost every widget that PAGE supports. This includes the Tk widgets, the ttk themed widgets, the enhanced widgets, and even a demonstration of using the custom widget. I decided to use a TNotebook with four tabs, one for each type of widget, and one that has a few tricks. During my creation of the demo, I realized I really didn’t have a low-level grasp of Styles and Themes. The subject is poorly documented, even in the Tcl/Tk world, and where there is documentation, many times the documentation is incorrect. Many programmers who use Tkinter either love or hate the ttk widgets, styles and themes. Many, like me, avoid the ttk widgets unless it’s an absolute necessity. When I am designing a GUI, more times than not, I will use the “standard” Tk widgets and use only the TCombobox, TNotebook, TNotebook, and the Treeview. Dealing with themes and styles is just too time consuming, at least in my mind, to be productive. Part of the confusion for many programmers is what exactly are Themes and what are Styles.
Styles concern the look and feel of a single widget. A Theme is a collection of Styles that share attributes like background colors and foreground colors, across many ttk widgets. While that is pretty easy to understand, for Linux, there are only four predefined Themes for the ttk widgets. They are Alt, Clam, Classic and Default. Those who use Windows have a couple of extra themes, but they aren’t available to Linux or Mac users, and the Mac has its own Themes that aren’t available to Linux or Windows users. And if you want to make your own, or at least modify one of the defaults, the documentation that exists is SO convoluted that it is often easier and more productive to just ignore the ttk widgets and deal with the Tk widgets. There are extra packages that a programmer can use to add more Themes, but many of them don’t seem to take many attributes of the widgets into consideration, so while they look good in general, things like the background of the TLabel doesn’t match the background of the container (or form) and there’s no obvious way to change it. To make matters worse, some of the containers, like the TFrame or TLabelframe, often don’t get a visible border. One of the most frustrating parts of creating the widget demo was fighting the TNotebook colors for the tabs. Take a look at this image:
You can see that Tab 2 is the current or selected tab, Tab 3 is sort of highlighted when the mouse is over the tab, and the other two are somewhat obvious that you aren’t dealing with them at the moment. But if you are color challenged, like me, it’s not always obvious. Wouldn’t it be better to be able to present your user with something like this: It is immediately obvious that Tab 1 is the current tab, Tabs 2, 4 and 5 are just “hanging out”, and Tab 3 is the one that the mouse is hovering over. You might not like the color selection, but it makes a big visual difference. But how to do it? Digging into the GUI.py file that PAGE creates gave me the first clue (see the code, next page, bottom right). The style.configure method allows you to set the basic background and foreground colors, but what does the style.map method do and why would I do it?
Well, with a bunch more digging around in various documentation and websites, I found out that the .map method allows you to set different colors to different states for the widget. So in the above code, the “selected” state is when the tab is actually selected and the “active” state is when the mouse is hovering over the tab. Notice that for the moment, we are only talking about the TNotebook tabs. But what about the other tabs that are “just hanging out”. That took some more digging to answer. It turns out that there is another state called “!active” that covers those tabs. Once I figured the hex codes for the colors I wanted I was ready. When I went to code it (shown top right), being the lazy programmer I am, I threw together a quick test program in PAGE with just a TNotebook on it and then created a startup function to set the colors and assign them to the widget. When I ran the program, I was disappointed. I quickly went back to the documentation and various websites to try to figure out what I was missing. It turns out that just setting the TNotebook map applies only to the actual Notebook portion. If I wanted to set the colors, I had to specify that the map was for the tabs (shown middle right). When I ran it this time, low and behold, it worked!
Then I tried to apply my new trick to other ttk widgets. Unfortunately, again, I was taking things for granted. For the most part, each ttk widget has its own set of attributes that the map can handle. For example, take the simple lowley TButton (next page, top right). The Tcl code shows that the TButton does have a map method, but the various states are far different from the TNotebook Tabs. There is an active state, a disabled state, and a readonly state. (Why would a TButton need a readonly state? I don’t know, but it apparently does.) So I reworked the code a bit for the TButton and came up with this (bottom right). When I then ran my program, I was disappointed again. The TButton had the default gray background and black text color set. When I moved the mouse over the TButton, it did change to background #2. I knew I was close, so I looked at the documentation a bit more closely. I remembered that I had to set the background and foreground separately from the map statement. _w1.TButton1.configure(background=bg1, foreground=fg1)
That, however, didn’t do it either. Then I remembered that I have to override the style defaults (dull gray background and black foreground). This is “explained” (somewhat) in the New Mexico Tech Tkinter documentation. It turns out that I can create a special style and apply that to my button by using the style attribute (shown bottom left). That worked! For more on the “Trials and Tribble-ations” of my long and arduous journey learning how to master Styles and Themes with ttk widgets in Tkinter, please see next month’s article. I’ll save the code portions for then. Until next time, as always; stay safe, healthy, positive and creative!