widget(n)
π NAME π
itcl::widget β creates a widget class of objects, and honestly? iconic behavior π
This is the widget page from [incr Tcl], bestie. Buckle up, it's a long one, and we're only on part 1 π¦
π WARNING! π
Okay so before we even start β this is new functionality in [incr Tcl] where the API can still change!! Like, fr fr. New. Shiny. Subject to change. Do not come for me if it shifts under you π
β¨ SYNOPSIS β¨
Here's the whole shape of it, copy it exactly, no cap:
itcl::widget widgetName {
inherit baseWidget ?baseWidget...?
constructor args ?init? body
destructor body
public method name ?args? ?body?
protected method name ?args? ?body?
private method name ?args? ?body?
public proc name ?args? ?body?
protected proc name ?args? ?body?
private proc name ?args? ?body?
public variable varName ?init? ?config?
protected variable varName ?init? ?config?
private variable varName ?init? ?config?
public common varName ?init?
protected common varName ?init?
private common varName ?init?
public command ?arg arg ...?
protected command ?arg arg ...?
private command ?arg arg ...?
<delegation info> see delegation page
<option info> see option page
set varName ?value?
array option ?arg arg ...?
}
widgetName objName ?arg arg ...?
objName method ?arg arg ...?
widgetName::proc ?arg arg ...?
See that <delegation info> line? Yeah, that's a whole other page β go read the delegation page for the tea π«. Same for <option info> β the option page has you covered β¨.
πΈ DESCRIPTION πΈ
So one of the fundamental constructs in [incr Tcl] is the widget definition. Think of a widget like a class, except it's got extra features bolted on β main character energy π.
Each widget acts as a template for actual objects that can be created. The widget itself is a namespace which contains things common to all the objects made from it. And each object gets its own unique little bundle of data β that bundle holds instances of the "variables" defined in the widget definition π.
Every object also has a built-in variable named "this", and it contains the name of the object. Handy, right? iykyk π
Widgets can also have "common" data members β those are shared by all objects in a widget. Like a group chat everyone's in π.
Two types of functions can live inside the widget definition, and the difference actually matters:
"Methods"β functions that operate on a specific object, so they get access to both"variables"and"common"data members π«Ά"Procs"β just ordinary procedures hanging out in the widget namespace, and they only get access to"common"data members π
Okay now here's a fun little detail π: if the body of any method or proc starts with "@", then it's treated as the symbolic name for a C procedure. Otherwise? It's treated as a Tcl code script. See below for the details on registering and using C procedures, bestie π
A widget can only be defined once β literally one time, periodt. But the bodies of widget methods and procs can be defined again and again, which is super useful for interactive debugging π¦. Wanna know the specifics? Go peek at the body and configbody commands.
Each namespace can have its own collection of objects and widgets, no cap. Wanna see what's available in the current context? Query it:
"itcl::find widgets"β lists the widgets available in the current context β¨"itcl::find objects"β lists the objects π
And when you're done with them π:
"delete widget"β deletes a whole widget"delete object"β deletes individual objects
okay that's the vibe so far, more parts incoming, don't go anywhere π
β¨ WIDGET DEFINITIONS β¨
So this is where you actually build the thing, bestie. Listen up π
widgetwidgetName definition β this hands you the definition for a widget named widgetName. Okay but here's the thing: if a widget called widgetName already exists, or if there's already a command named widgetName hanging out in the current namespace context, this command just straight up returns an error. No duplicates, no drama. But if the definition parses cleanly? widgetName becomes a command in the current context, and it's the one handling the creation of objects for this widget. Main character energy fr fr π
The widget definition gets evaluated as a series of Tcl statements that define the elements inside the widget. Here are the widget definition commands it recognizes β every single one, no skipping π:
πΈ inherit baseWidget ?baseWidget...?
Causes the current widget to inherit characteristics from one or more base widgets. Those widgets must have been defined by a previous widget command, or they need to be available to the auto-loading facility (peep "AUTO-LOADING" below π). And heads up: a single widget definition can contain no more than one inherit command. One. That's it. Don't push it.
The order of the baseWidget names in the inherit list matters for name resolution of widget members. When the same member name shows up in two or more base widgets, whichever base widget appears first in the inherit list takes precedence. For example, if widgets Foo and Bar both contain the member x, and another widget has this inherit statement:
inherit Foo Bar
then the name x means Foo::x. Any other inherited members named x have to be referenced with their explicit name, like Bar::x. iykyk π«Ά
π constructor args ?init? body
Declares the args argument list and body used for the constructor, which gets automatically invoked whenever an object is created. It's giving "surprise, I'm here" but like, scheduled.
Before the body runs, the optional init statement is used to invoke any base widget constructors that require arguments. Variables in the args specification can be accessed in the init code fragment, and passed to base widget constructors. After evaluating the init statement, any base widget constructors that haven't been executed get invoked automatically without arguments. This makes sure all base widgets are fully constructed before the constructor body is executed. By default, this scheme causes constructors to be invoked in order from least- to most-specific. And that is exactly the opposite of the order that widgets are reported by the info heritage command. Chaos, but organized chaos π
If construction is successful, the constructor always returns the object name β regardless of how the body is defined β and the object name becomes a command in the current namespace context. If construction fails, you get an error message back.
π¦ destructor body
Declares the body used for the destructor, which is automatically invoked when an object is deleted. If the destructor is successful, the object data is destroyed and the object name is removed as a command from the interpreter. If destruction fails, an error message is returned and the object remains. It literally refuses to leave. iconic behavior honestly π
When an object is destroyed, all destructors in its widget hierarchy are invoked in order from most- to least-specific. That's the order the widgets are reported by the info heritage command, and it's exactly the opposite of the default constructor order. (Yes, we said that before. It's important. Let it sink in. π§)
π method name ?args? ?body?
Declares a method called name. When the method body is executed, it has automatic access to object-specific variables and common data members. Lucky them β¨
If the args list is specified, it establishes the usage information for this method. The body command can be used to redefine the method body, but the args list must match this specification. No switching up the args mid-relationship, bestie.
Within the body of another widget method, a method can be invoked like any other command β simply by using its name. Outside of the widget context though, the method name must be prefaced with an object name, which provides the context for the data that it manipulates. Methods in a base widget that are redefined in the current widget, or hidden by another base widget, can be qualified using the widgetName::method syntax. Slay π
π proc name ?args? ?body?
Declares a proc called name. A proc is an ordinary procedure within the widget namespace. Unlike a method, a proc is invoked without referring to a specific object. When the proc body is executed, it has automatic access only to common data members. That's the whole difference, and honestly it's a big one π
If the args list is specified, it establishes the usage information for this proc. The body command can be used to redefine the proc body, but the args list must match this specification.
Within the body of another widget method or proc, a proc can be invoked like any other command β simply by using its name. In any other namespace context, the proc is invoked using a qualified name like widgetName::proc. Procs in a base widget that are redefined in the current widget, or hidden by another base widget, can also be accessed via their qualified name. Full legal name only, no nicknames π₯
π variable varName ?init? ?config?
Defines an object-specific variable named varName. All object-specific variables are automatically available in widget methods β they do not need to be declared with anything like the global command. So chill, you don't have to do the paperwork πΈ
If the optional init string is specified, it's used as the initial value of the variable when a new object is created. Heads up tho: initialization forces the variable to be a simple scalar value. Uninitialized variables, on the other hand, can be set within the constructor and used as arrays. Balance β¨
The optional config script is only allowed for public variables. If specified, this code fragment is executed whenever a public variable is modified by the built-in configure method. The config script can also be specified outside of the widget definition using the configbody command. Flexible queen π
π§ common varName ?init?
Declares a common variable named varName. Common variables reside in the widget namespace and are shared by all objects belonging to the widget. They're just like global variables, except they don't need to be declared with the usual global command. They're automatically visible in all widget methods and procs. Communal living, but make it Tcl π«Ά
If the optional init string is specified, it's used as the initial value of the variable. Initialization forces the variable to be a simple scalar value; uninitialized variables, on the other hand, can be set with subsequent set and array commands and used as arrays.
Once a common data member has been defined, it can be set using set and array commands within the widget definition. This lets common data members be initialized as arrays. For example:
itcl::widget Foo {
protected common boolean
set boolean(true) 1
set boolean(false) 0
}
β οΈ Note that if common data members are initialized within the constructor, they get initialized again and again whenever new objects are created. Like, every single time. It's giving "forgot I already did that" π
π public command ?arg arg ...?
π protected command ?arg arg ...?
π private command ?arg arg ...?
These three are the protection-level squad and they work the same way. They're used to set the protection level for widget members that are created when command is evaluated. The command is usually method, proc, variable or common (and yes, the manpage really does write variable orcommon like that β no space, we're keeping it exactly as it is π), and the remaining arg's complete the member definition.
But wait, there's more: command can also be a script containing many different member definitions, and the protection level will apply to all of the members that are created. Bulk protection. Efficiency. We love to see it π
π¦ WIDGET USAGE π¦
Once a widget has been defined, the widget name can be used as a command to create new objects belonging to the widget. Yes bestie, that's the payoff π
π« widgetName objName ?args...?
Creates a new object in widget widgetName with the name objName. Remaining arguments are passed to the constructor of the most-specific widget. That in turn passes arguments to base widget constructors before invoking its own body of commands. Chain of command, literally β¨
If construction is successful, a command called objName is created in the current namespace context, and objName is returned as the result of this operation. If an error is encountered during construction, the destructors are automatically invoked to free any resources that have been allocated, the object is deleted, and an error is returned. Cleanup crew on standby π§Ή
Now, the fun part: if objName contains the string #auto, that string is replaced with an automatically generated name. Names have the form widgetName<number>, where the widgetName part is modified to start with a lowercase letter. In widget Toaster, for example, the #auto specification would produce names like toaster0, toaster1, etc. And yes, #auto can also be buried inside an object name:
fileselectiondialog .foo.bar.#auto -background red
This would generate an object named .foo.bar.fileselectiondialog0. Not me being obsessed with buried auto-names ππ
π OBJECT USAGE π
Okay so once an object has been created, the object name literally becomes a command you can use to invoke methods that operate on that object. Main character behavior, honestly.
objName method ?args...?β Invokes a method named method on an object named objName. The remaining arguments get passed to the argument list for the method. The method name can beconstructor,destructor, any method name appearing in the widget definition, or any of the following built-in methods. Slay.
β¨ BUILT-IN METHODS β¨
objName cget optionβ Provides access to public variables as configuration options. This mimics the behavior of the usualcgetoperation for Tk widgets. The option argument is a string of the form-varName, and this method returns the current value of the public variable varName. Cute, right?objName configure ?option? ?value option value ...?β Provides access to public variables as configuration options. This mimics the behavior of the usualconfigureoperation for Tk widgets.
With no arguments, this method returns a list of lists describing all of the public variables. Each list has three elements: the variable name, its initial value and its current value. Three-element lists are lowkey iconic.
If a single option of the form -varName is specified, then this method returns the information for that one variable.
Otherwise, the arguments are treated as option/value pairs assigning new values to public variables. Each variable is assigned its new value, and if it has any "config" code associated with it, it is executed in the context of the widget where it was defined. If the "config" code generates an error, the variable is set back to its previous value, and the configure method returns an error. No cap, it undoes the vibe.
objName isa widgetNameβ Returns non-zero if the given widgetName can be found in the object's heritage, and zero otherwise. Heritage check, bestie.objName info option ?args...?β Returns information related to a particular object named objName, or to its widget definition. The option parameter includes the following things, as well as the options recognized by the usual Tclinfocommand:objName info widgetβ Returns the name of the most-specific widget for object objName.objName info inheritβ Returns the list of base widgets as they were defined in theinheritcommand, or an empty string if this widget has no base widgets.objName info heritageβ Returns the current widget name and the entire list of base widgets in the order that they are traversed for member lookup and object destruction. It's giving ancestry dot com.objName info function ?cmdName? ?-protection? ?-type? ?-name? ?-args? ?-body?β With no arguments, this command returns a list of all widgets methods and procs. If cmdName is specified, it returns information for a specific method or proc. If no flags are specified, this command returns a list with the following elements: the protection level, the type (method/proc), the qualified name, the argument list and the body. Flags can be used to request specific elements from this list.objName info variable ?varName? ?-protection? ?-type? ?-name? ?-init? ?-value? ?-config?β With no arguments, this command returns a list of all object-specific variables and common data members. If varName is specified, it returns information for a specific data member. If no flags are specified, this command returns a list with the following elements: the protection level, the type (variable/common), the qualified name, the initial value, and the current value. If varName is a public variable, the"config"code is included on this list. Flags can be used to request specific elements from this list. Big "ask and you shall receive" energy.
π CHAINING METHODS/PROCS π
Sometimes a base widget has a method or proc that is redefined with the same name in a derived widget. This is a way of making the derived widget handle the same operations as the base widget, but with its own specialized behavior. Obsessed with the inheritance drama.
For example, suppose we have a Toaster widget that looks like this:
itcl::widget Toaster {
variable crumbs 0
method toast {nslices} {
if {$crumbs > 50} {
error "== FIRE! FIRE! =="
}
set crumbs [expr {$crumbs+4*$nslices}]
}
method clean {} {
set crumbs 0
}
}
We might create another widget like SmartToaster that redefines the toast method. If we want to access the base widget method, we can qualify it with the base widget name, to avoid ambiguity:
itcl::widget SmartToaster {
inherit Toaster
method toast {nslices} {
if {$crumbs > 40} {
clean
}
return [Toaster::toast $nslices]
}
}
Instead of hard-coding the base widget name, we can use the chain command like this:
itcl::widget SmartToaster {
inherit Toaster
method toast {nslices} {
if {$crumbs > 40} {
clean
}
return [chain $nslices]
}
}
The chain command searches through the widget hierarchy for a slightly more generic (base widget) implementation of a method or proc, and invokes it with the specified arguments. It starts at the current widget context and searches through base widgets in the order that they are reported by the info heritage command. If another implementation is not found, this command does nothing and returns the null string. It's giving "respectfully, find someone else to do it" and honestly same.
π¦ AUTO-LOADING π¦
Widget definitions need not be loaded explicitly; they can be loaded as needed by the usual Tcl auto-loading facility. Each directory containing widget definition files should have an accompanying tclIndex file. Each line in this file identifies a Tcl procedure or [incr Tcl] widget definition and the file where the definition can be found.
For example, suppose a directory contains the definitions for widgets Toaster and SmartToaster. Then the tclIndex file for this directory would look like:
# Tcl autoload index file, version 2.0 for [incr Tcl]
# This file is generated by the "auto_mkindex" command
# and sourced to set up indexing information for one or
# more commands. Typically each line is a command that
# sets an element in the auto_index array, where the
# element name is the name of a command and the value is
# a script that loads the command.
set auto_index(::Toaster) "source $dir/Toaster.itcl"
set auto_index(::SmartToaster) "source $dir/SmartToaster.itcl"
The auto_mkindex command is used to automatically generate tclIndex files. Magic, but make it administrative.
The auto-loader must be made aware of this directory by appending the directory name to the auto_path variable. When this is in place, widgets will be auto-loaded as needed when used in an application. It's like your fave showing up exactly when you need them. π«Ά
π₯ C PROCEDURES π₯
C procedures can be integrated into an [incr Tcl] widget definition to implement methods, procs, and the "config" code for public variables. Any body that starts with "@" is treated as the symbolic name for a C procedure.
Symbolic names are established by registering procedures via Itcl_RegisterObjC(). This is usually done in the Tcl_AppInit() procedure, which is automatically called when the interpreter starts up. In the following example, the procedure My_FooObjCmd() is registered with the symbolic name "foo". This procedure can be referenced in the body command as "@foo".
int
Tcl_AppInit(interp)
Tcl_Interp *interp; /* Interpreter for application. */
{
if (Itcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
if (Itcl_RegisterObjC(interp, "foo", My_FooObjCmd) != TCL_OK) {
return TCL_ERROR;
}
}
C procedures are implemented just like ordinary Tcl commands. See the CrtCommand man page for details. Within the procedure, widget data members can be accessed like ordinary variables using Tcl_SetVar(), Tcl_GetVar(), Tcl_TraceVar(), etc. Widget methods and procs can be executed like ordinary commands using Tcl_Eval(). [incr Tcl] makes this possible by automatically setting up the context before executing the C procedure. It's serving "I got you, bestie" behind the scenes.
This scheme provides a natural migration path for code development. Widgets can be developed quickly using Tcl code to implement the bodies. An entire application can be built and tested. When necessary, individual bodies can be implemented with C code to improve performance. Start cute and Tcl, then go fast and C. Periodt.
πΈ KEYWORDS πΈ
widget, object, object-oriented
That's the whole page, bestie! Source itcl, version 4.0, manual page widget(n) β and the date is the one stamped in that footer, cute as ever. Mwah ππ
π¦ where this page comes from
- alpine 3.23: tcl-doc 8.6.17-r0 Β· TCL
- alpine 3.23: tcl9-doc 9.0.3-r0 Β· TCL
- alpine 3.24: tcl-doc 8.6.17-r1 Β· TCL
- alpine 3.24: tcl9-doc 9.0.3-r2 Β· TCL
- nixos 26.05: tcl 9.0.3
- nixpkgs unstable: tcl 9.1.0
- Copyright (c) 2008 Arnulf Wiedemann
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms