ttk::intro(n)
π ttk::intro β like, the whole vibe of the Tk theme engine, explained
okay so this is ttk::intro(n) from the Tk Themed Widget manual, and honestly? it's giving "read this first or you will cry." let's get into it π«Ά
πΈ OVERVIEW πΈ
The Tk themed widget set is built on a revised and enhanced version of the style engine from TIP #48 (https://tip.tcl-lang.org/48) β yes, that's a real spec, go look at it if you're feeling academic. The main concepts are all down below, but here's the β¨thesis statementβ¨:
Separate, as much as humanly possible, the code that implements a widget's behavior from the code that implements its appearance. That's it. That's the whole philosophy.
Widget class bindings are mainly responsible for maintaining widget state and invoking callbacks. Everything about how the widget looks β literally every aspect β is controlled by the widget's style (like, the style of the elements of the widget). behavior brain π§ vs. aesthetic brain π, two different departments, no cap.
π THEMES π
A theme is a collection of elements and styles that decide the look and feel of the widget set. Think of it as an outfit for your entire application. Themes can be used to:
- isolate platform differences (X11 vs. classic Windows vs. XP vs. Aqua ...) β hello, cross-platform queen π
- adapt to display limitations (low-color, grayscale, monochrome, tiny screens) β being flexible is a flex
- accessibility (high contrast, large type) β this one's important, bestie, don't skip it π
- application suite branding
- blend in with the rest of the desktop (Gnome, KDE, Java) β camouflage, but make it fashion
- and, of course: eye candy. β¨ periodt.
π¦ ELEMENTS π¦
An element displays one individual part of a widget. Example: a vertical scrollbar widget contains uparrow, downarrow, trough and slider elements. Four little icons doing their job. iconic.
Element names use a recursive dotted notation. So uparrow identifies a generic arrow element, while Scrollbar.uparrow and Combobox.uparrow identify widget-specific elements β same arrow, different context, iykyk.
When the style engine goes looking for an element, it looks for the specific name first. If no element by that name exists, it looks for generic elements by stripping off successive leading components of the element name. so it's like, "do I know this one specifically? no? okay then, who are your parents" π
Like widgets, elements have options that specify what to display and how to display it. For example, the text element (which displays a text string) has -text, -font, -foreground, -background, -underline, and -width options.
The value of an element option is taken from β in precedence order:
- an option of the same name and type in the widget containing the element;
- a dynamic setting specified by
style mapand the current state; - the default setting specified by
style configure; or - the element's built-in default value for the option.
that's the priority queue, top wins. no cap π«Ά
π§ LAYOUTS π§
A layout specifies which elements make up a widget and how they're arranged. The layout engine uses a simplified version of the pack algorithm: you start with an initial cavity equal to the size of the widget, then elements are allocated a parcel within the cavity along the side specified by the -side option, and placed within the parcel according to the -sticky option. it's giving tetris but polite.
For example, the layout for a horizontal scrollbar is:
ttk::style layout Horizontal.TScrollbar {
Scrollbar.trough -children {
Scrollbar.leftarrow -side left -sticky w
Scrollbar.rightarrow -side right -sticky e
Scrollbar.thumb -sticky ew
}
}
By default, the layout for a widget is the same as its class name. Some widgets may override this β for example, the ttk::scrollbar widget chooses different layouts based on the -orient option. main character energy, honestly.
β STATES β
In standard Tk, many widgets have a -state option which (in most cases) is either normal or disabled. Some widgets support additional states β like the entry widget which has a readonly state, and the various flavors of buttons which have an active state.
The themed Tk widgets generalize this idea: every widget has a bitmap of independent state flags. Widget state flags include active, disabled, pressed, focus, etc. (see ttk::widget(n) for the full list of state flags β go read it, I'll wait π).
Instead of a -state option, every widget now has a state widget command which is used to set or query the state. A state specification is a list of symbolic state names indicating which bits are set, each optionally prefixed with an exclamation point indicating that the bit is cleared instead. ! = "not this one," basically.
For example, the class bindings for the ttk::button widget are:
bind TButton <Enter>{ %W state active }
bind TButton <Leave>{ %W state !active }
bind TButton <Button-1>{ %W state pressed }
bind TButton <Button1-Leave>{ %W state !pressed }
bind TButton <Button1-Enter>{ %W state pressed }
bind TButton <ButtonRelease-1>\
{ %W instate {pressed} { %W state !pressed ; %W invoke } }
so what's happening here, bestie:
- the widget becomes
activewhen the pointer enters the widget, and inactive (!active) when it leaves πΈ - similarly it becomes
pressedwhen the mouse button is pressed, and!pressedon theButtonReleaseevent - in addition, the button unpresses if the pointer is dragged outside the widget while Button-1 is held down, and represses if it's dragged back in π
- finally, when the mouse button is released, the widget's
-commandis invoked, but only if the button is currently in thepressedstate
(and ngl, the actual bindings are a little more complicated than the above β but not by much π)
π STYLES π
Each widget is associated with a style, which specifies values for element options. Style names use a recursive dotted notation like layouts and elements; by default, widgets use the class name to look up a style in the current theme.
For example:
ttk::style configure TButton \
-background #d9d9d9 \
-foreground black \
-relief raised \
;
Many elements are displayed differently depending on the widget state. For example, buttons have a different background when they're active, a different foreground when disabled, and a different relief when pressed. The style map command specifies dynamic option settings for a particular style:
ttk::style map TButton \
-background [list disabled #d9d9d9 active #ececec] \
-foreground [list disabled #a3a3a3] \
-relief [list {pressed !disabled} sunken] \
;
look at that state-conditional gorgeousness. {pressed !disabled} is literally "pressed AND not disabled" and I'm obsessed π₯
π SEE ALSO π
ttk::widget(n)β the full state flag list lives herettk::style(n)β where all the style commands hang out
ok that's the whole page bestie, every flag and every example, nothing skipped. go build something cute π
and that's a wrap, brought to you by Tk 8.5 β ttk::intro(n), as documented in the Tk Themed Widget manual. slay πβ¨π
π¦ where this page comes from
- alpine 3.23: tk9-doc 9.0.3-r0 Β· TCL
- alpine 3.24: tk9-doc 9.0.3-r2 Β· TCL
- fedora 43: tk 1:9.0.2-1.fc43 Β· TCL AND HPND-Pbmplus AND CC-BY-SA-3.0 AND MIT-open-group AND MIT
- fedora 43: tk 1:9.0.2-1.fc43 Β· TCL AND HPND-Pbmplus AND CC-BY-SA-3.0 AND MIT-open-group AND MIT
- fedora 44: tk 1:9.0.2-1.fc44 Β· TCL AND HPND-Pbmplus AND CC-BY-SA-3.0 AND MIT-open-group AND MIT
- fedora 44: tk 1:9.0.2-1.fc44 Β· TCL AND HPND-Pbmplus AND CC-BY-SA-3.0 AND MIT-open-group AND MIT
- nixos 26.05: tk 9.0.3
- nixpkgs unstable: tk 9.1.0
- Copyright (c) 2004 Joe English
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms