ttk::style

Introduction

A Ttk command that manipulates styles and themes. The information below refers to tile 0.8 and upwards.

Find the manual page for this command here:
http://tktable.sourceforge.net/tile/doc/style.html
https://www.tcl-lang.org/man/tcl8.5/TkCmd/ttk_style.htm

A tutorial-style introduction to ttk styles is here: http://www.tkdocs.com/tutorial/styles.html


How do styles work?

A style is assigned to a Ttk widget and specifies the set of elements making up the widget and how they are arranged, along with dynamic and default settings for element options. This is from the manual page. What does this mean?

First, let us just state: a style is specific for a widget, or rather a widget type, like ttk::frame or ttk::combobox. A ttk theme is a collection of styles belonging together and giving a consistent look and feel to all widgets.

Now, let us take the above statements one by one:

The style specifies the set of elements making up the widget

So, each widget is built using definable elements. A 'simple' label, for example, is made by using 3 different parts: a border element, a padding element, and the actual text of the label element. All three elements together form the ttk label widget.

How do we know what elements are used in the standard ttk widgets? This is what the command 'ttk::style layout' is for:

% ttk::style layout TLabel
Label.border -sticky nswe -border 1 -children {Label.padding -sticky nswe -border 1 -children {Label.label -sticky nswe}}

What you get is a description of the elements of the widget and how these elements are arranged (see next section). The words starting with the capital L are the elements: Label.border, Label.padding, and Label.label. How did we know to ask for TLabel in the above command? Well, the layout command requires a style name as an argument, and by default, the style name is the same as the widget's class name (this may be overridden by the -style option, if some code changes a widget). The class name is obtained by winfo class and you need to already have a widget created:

 % ttk::label .l
 % winfo class .l
 TLabel

If the widget already was changed by using the -style option, you can get the custom style name querying this option:

 % # assumng the custom style MyStyle.TLabel is already defined:
 % ttk::label .k -style MyStyle.TLabel
 % .k cget -style
 MyStyle.TLabel
 % # this would return the empty string, if the widget had no custom style

The style specifies how the elements are arranged

This is called the layout of the elements and we just saw it in the code above. The three elements mentioned above need to be arranged in a specific manner to look good and be useful. Let's take it again:

 % ttk::style layout TLabel
 Label.border -sticky nswe -border 1 -children {Label.padding -sticky nswe -border 1 -children {Label.label -sticky nswe}}

So, first comes the border and it sticks to the four corners of the space, which is assigned to the widget (-sticky nswe). The border has a border (funny, right?) of 1 (-border 1) and then it has some children. This means there is something inside the border. In our case, there is the second element inside: the padding. The padding is also sticky so it sticks to all four corners and it also has a border. The child of the padding is the actual label and the label also sticks to all four corners.

Now, children can be more than one element. The children option takes a list of elements, for example the scrollbar:

 % ttk::style layout Horizontal.TScrollbar
 Horizontal.Scrollbar.trough -sticky we -children {
     Horizontal.Scrollbar.leftarrow -side left -sticky {}
     Horizontal.Scrollbar.rightarrow -side right -sticky {}
     Horizontal.Scrollbar.thumb -expand 1 -sticky nswe
 }

The command does actually not return the layout formatted as above but this was done to see the individual elements of the last child in the horizontal scollbar widget.

The style specifies dynamic and default settings for element options

What font should the label use by default? Should the font change when the label is in different states (normal, disabled)? All this behaviour is defined by the style. The answers to these kind of questions is found using the ttk::style lookup command:

 % ttk::style lookup TLabel -font
 TkDefaultFont
 % ttk::style lookup TLabel -foreground
 black

This is but half the truth. The above command returns the values for the normal state. What about the 'disabled' state? Do this:

 % ttk::style lookup TLabel -foreground disabled
 #a3a3a3
 % ttk::style lookup TLabel -font disabled
 TkDefaultFont

So, in the disabled state, the font is the same, but the color is a gray shade.


Define your own style

See here http://www.tkdocs.com/tutorial/styles.html for a starting point.


How do I give a specific widget a specific color?

Suppose, you have a labelframe and want another foreground color for the label, say yellow. Since the label uses a sublayout to draw the actual label for the frame, you need to alter the configuration of TLabelframe.Label since this is the part of the layout that defines the label. Simply do:

 % ttk::style configure TLabelframe.Label -foreground yellow
 % ttk::labelframe .something
 % pack .something

See also [L1 ].


All this was taken from man pages and some threads on comp.lang.tcl: [L2 ], [L3 ]


A user on the MacTcl mailing list asked about this exchange:

% ::ttk::style lookup TButton -font
System
% font configure System
named font "System" doesn't exist

Another member (Damon Courtney), in response, suggested using

font create System {*}[font actual System] 
font configure System -size 16 -weight bold

and indicated that by creating a named font, one gains the ability to override attributes of the actual System font. Daniel Steffen followed that recommendation with the following:

the "system", "application" and "menu" native font names should be avoided now that we have named fonts, instead use the TIP145 standard named fonts "TkDefaultFont", "TkTextFont" and "TkMenuFont" or the equivalent platform named fonts "systemSystemFont", "systemApplicationFont" and "systemMenuItemFont" (c.f. font.n for the full list of named fonts).
That ttk/aquaTheme.tcl was still using the "system" native font name was a bug, I've just committed a fix that replaces that name by "TkDefaultFont", and uses system color names instead of hardcoded color values.

How to change the layout of a widget

The layout of a ttk::checkbutton can be obtained with this command:

ttk::style layout TCheckbutton

and looks like this:

Checkbutton.padding -sticky nswe -children {Checkbutton.indicator -side left -sticky {} Checkbutton.focus -side left -sticky w -children {Checkbutton.label -sticky nswe}}

Schelte Bron explained on the Tcler's chat how to create a new layout with indicator and text swapped:

ttk::style layout Swap.TCheckbutton {
  Checkbutton.padding -sticky nswe -children {
    Checkbutton.indicator -side right -sticky {}
    Checkbutton.focus -side left -sticky w -children {
      Checkbutton.label -sticky nswe
    }
  }
}

# Plain checkbutton
pack [ttk::checkbutton .c1 -text c1]
# Checkbutton with text and indicator swapped
pack [ttk::checkbutton .c2 -text c2 -style Swap.TCheckbutton]

Here's how a ttk::spinbox can be changed to have its spinbuttons on either side of the entry field (tested with clam theme):

ttk::style layout Axial.TSpinbox {
  Entry.field -side top -sticky we -children {
    Horizontal.Scrollbar.leftarrow -side left -sticky ns
    Horizontal.Scrollbar.rightarrow -side right -sticky ns
    Spinbox.padding -sticky nswe -children {
      Spinbox.textarea -sticky nswe
    }
  }
}
ttk::style configure Axial.TSpinbox -padding {2 0}

pack [ttk::spinbox .sp -to 100 -style Axial.TSpinbox -justify right]

See the ttk::style examples page for examples of using the ttk::style command.


2011/05/22 Aud – Element creation within Tcl scripts is a really neat concept, but unfortunately it seems unrefined and inflexible right now, compared to what you could do in C. I'm interested in creating my own widget styles using my own elements, coded in pure Tcl (which seems like it might've been one of Tile's original goals). It's doable with ttk_image, but the downside seems to be that you can't manage the elements at all once they're created; they can't be dynamically configured.


  Get current theme over tile/ttk versions

HaO 2012-04-11: Within ttk development, there were 3 methods to get the current theme over. The following code sets the variable currentTheme by trying all methods:

if {    [catch {ttk::style theme use} currentTheme]
        || [catch {set ::ttk::currentTheme} currentTheme]
} {
    set currentTheme $::tile::currentTheme
}

The first access ttk::style theme use is currently not necessary as it is an access method to the variable ::ttk::currentTheme. Nevertheless, is it more future-save to use this documented access function in case the interals may change.