Outils pour utilisateurs

Outils du site


issue183:python

Ceci est une ancienne révision du document !


Sorry about not being able to continue the topic last month, but we are back. Let’s jump right into the project where we left on in issue #181. Here is what the latest version of the program looks like (image shown bottom right)

Just to remind you, there are three possible color settings for most widgets. A Selected Background color, an Active Background color, and an Inactive Background color. Here is how they work…

For the most part, this all pertains to the TNotebook Tabs, but have “carry overs” into most other widgets as well. Select Background Color - The background color of the tab (widget) you are currently on Active Background Color - The background of the tab (widget) the mouse is hovering over Inactive Background Color - The background of all other tabs (widgets)

Most of the action happens within the TNotebook. There are three main panels (all TLableframes (ttk::Labelframes)) that hold the widgets that we will need to make the project work. From left to right, we have the background colors, the foreground colors, and a small sampling of various widgets that will act as a preview, showing how the colors will look.

Taking a closer look at the background colors TLableframe (the foreground works almost exactly the same, except for dealing with the foreground colors), we’ll concentrate on the background panel right now. We have three static text widgets (ttk::Labels), three Entry widgets (ttk:Entries), and three Buttons (Standard Tk::Buttons). Between the Entry widgets and the buttons, we can pick the colors we want to try. All three buttons have the same basic callback command function (lambda : on_bgColor(x) where x is the number of the button). This allows any of the three buttons to call the same function, with a different index, so the program knows which Button made the call. The buttons will call the ColorSelect dialog. If you know what color you want, you can put the color directly into the Entry box of the Labelframe or use the dialog. The dialog also lets you use the sliders or direct entry into the Entry box.

Here is what you need to use the ColorSelect dialog.

First, you need to import it from Tkinter.

import tkinter.colorchooser as colorchooser

Then, when you want the colorchooser dialog to be shown, the syntax is:

result = tkColorChooser.askcolor(color, option=value, …)

The parameters are: Color - The initial color that the dialog will show. If you leave it blank, it will default to light gray. Title - The title for the dialog window Parent - The Toplevel form you wish the dialog to appear over. Usually, this would be your main form.

The return value comes back as a tuple that comes in as (triple, color) – assuming the user clicks the Ok button. Triple is itself a tuple of (Red, Green, Blue) values (in the range of [0, 255]) and color is the regular Tkinter hex value object. If the user clicks the Cancel button, the return value will be (None,None).

When the dialog is shown, the user can use the sliders to create a color they like, enter a hex value (starting with “#”) into the entry box, or enter one of the predefined Tkinter colors as a string (like “sky blue”). Any time you enter something into the entry box of the dialog, you MUST press the Enter key to “set” the information before you click the ok button (top right).

The TEntry widgets each have a textvar that allows the program to find the entered data simply and they are TEntry1Data, TEntry2Data and TEntry3Data. I’ve bound the three TEntry widgets to the same callback function whenever a key is pressed on the keyboard and the widget is in focus. In this function, we are only looking for the <Return> key, Then we simply read the text var to see what the user has entered.

Now let’s look at some of the code that is attached to the buttons. Remember, we call the code as on_bgColor(n) where n is the value we gave the button.

For the most part, the first portion of the code is generated by PAGE, showing each of the values passed into the function. I added the global statement and the if debug: portion of the code, so I can hide the value printout when I’m done with debugging.

Next we look at the argument being passed in (which is the number of the button) and get the last color that was assigned to that background color group from the globals. This gives us the starting color for the Color Select dialog based on which of the three background colors we wish to work on.

We simply use an if statement to check the value passed in.

  which = args[0]
  if which == 1:
      colr = lastbg1
  elif which == 2:
      colr = lastbg2
  elif which == 3:
      colr = lastbg3

Simple enough, right? Now that we have the basic data, we can call the colorchooser dialog.

result = colorchooser.askcolor(

      
colr, title=f"Enter Color for Background #{which}", parent=root)

We set the starting color, the title of the dialog, and the name of the parent Toplevel so the dialog gets centered properly. The response from the user comes back as the variable result.

Since the dialog returns two values (the first being a tuple containing R,G and B value, and the second returning the hex value of the color chosen), we need to check at least one of the two values. Tkinter doesn’t allow for the RGB values to be used directly, so we want to check the hex value which comes in as the second value. In addition, the values can be either valid color values or two None values. I opted to check the second value, which is what we will be using to set the color if there is a value there. The first thing we to do is make sure that the user didn’t click the Cancel button (bottom left).

If the returned value is not None, we then set the hex value into the TEntry widget and set the background color of the button to visually show the color that was chosen. The same code is basically used for the other two possible button/TEntry combinations. Then, finally we call the root.update() function just to make sure everything looks right (bottom right).

The Foreground color (the text color) is basically the same process, so we’ll skip it here for this month. So here is what a simple color combination works out to be. Selected Background is Tab 1, Tab 2 is the Active background (where the mouse is hovering), and Tabs 3 through 5 are the Inactive Backgrounds.

In order to get the colors to actually be applied to the widgets, we need to apply the colorsets.

Looking back at the full image of the form, there is a button called “Apply Colors”. This has a callback that simply calls a function called set_colors(). Since I originally designed this to deal with ttk widgets, we need to start by calling the ttk.Style() to get a default style structure.

def set_colors():

  global lastbg1, lastbg2, lastbg3, lastfg1, lastfg2, lastfg3
  # =================================================
  style = ttk.Style()

In order to manipulate any of the styles for any of the ttk widgets, we have to modify the style.map structure. Since we want to change the TNotebook tabs first, we start there (top right).

Each ttk widget has a different set of states that can be set. These can include states like “Active”, “Disabled”, “Background” and more. You can see that we set the three background and three foreground color values above. What is not obvious from the documentation on ttk Style manipulation is the inactive state. “Selected” and “Active” are all obvious, but there is the “!active” state, which is the inactive state (when the widget is just sitting there without the mouse doing anything around it).

As I said, every widget is different as to the states that it will support. For example, the TButton has an “Active”, a “Disabled” and a “Readonly” state, all of which have separate attributes that can be set (bottom left).

Many of the ttk widgets also need to be configured, sort of like the “standard” Tk widgets do, to set many of the various attributes available. To do this, we need to create a “generic” style for that widget, then apply it using the style attribute. (Gets somewhat confusing, huh?.

We do this by using the style.configure function, starting with our named style along with the widget, then set the attributes as we want them, then finally applying the style via the style attribute (bottom right).

You can do this with many of the “normal” attributes that you don’t get to change within PAGE, since any ttk widget can have any style available. Imagine having 100 ttk widgets each with its own style. It can be done!

Enough theory for this month. Next month, we’ll look at saving the colorsets into something that we can use and apply, and a way to write this information out so we can use it within other programs in a very simple way.

Until next time, as always; stay safe, healthy, positive and creative!

issue183/python.1659122153.txt.gz · Dernière modification : 2022/07/29 21:15 de d52fr