menubar(n)

πŸ“¦ version 0.7, in alpine 3.24

🌸 NAME 🌸

menubar(n) β€” Create and manipulate menubars. Creates an instance of the menubar Class. πŸ’…


✨ SYNOPSIS ✨

package require Tcl  8.6

package require Tk  8.6

package require menubar  ?0.5?

menubar new ?options?

mBarInst define body

mBarInst install pathName body

mBarInst menu.configure option tag-settings ?option tag-settings ...?

mBarInst menu.namespace tag namespace

mBarInst menu.hide tag

mBarInst menu.show tag

mBarInst tag.add tag value

mBarInst tag.configure pathName tag ?option value ...option value?

mBarInst tag.cget pathName tag ?option?

mBarInst group.add tag label ?cmd? ?accel? ?sequence? ?state?

mBarInst group.delete tag label

mBarInst group.move direction tag label

mBarInst group.configure tag label ?option value ...option value?

mBarInst group.serialize tag

mBarInst group.deserialize tag stream

mBarInst notebook.addTabStore pathname

mBarInst notebook.deleteTabStore pathname

mBarInst notebook.setTabValue pathname tag

mBarInst notebook.restoreTabValues pathname

πŸ’– DESCRIPTION πŸ’–

menubar new ?options?

okay so this creates and returns a new instance of the menubar class. The menubar class encapsulates the definition, installation and dynamic behavior of a menubar. The class doesn't depend on a widget framework and therefore can be used with or without a framework (e.g. Bwidget, IWidget, Snit, etc.). Unlike other Tk widget commands, the menubar command doesn't have a pathName argument because menubars are handled by the window manager (i.e. wm) and not the application. iconic behavior, honestly ✨


πŸŽ€ OPTIONS πŸŽ€

The following options can be passed to the menubar new command.

These options are inherited from the Tk menu command, their effect is platform specific.

vibe check: these are inherited from Tk menu, so their effect is platform specific. no cap. πŸŽ€

πŸ¦‹ INTRODUCTION πŸ¦‹

An instance of the menubar class provides methods for compiling a description of the menubar, configuring menu items and installing the menubar in toplevel windows.

A menubar can be thought of as a tree of cascading menus. Users define a menubar using a language that results in a human readable description of a menubar. The description of the menubar is then compiled by an instance of the menubar class after which it can be installed in one or more toplevel windows. the way that works is lowkey elegant πŸ¦‹

The menubar class provides many unique capabilities that are not found in other tcl/tk menubar implementation. Some of these are:

  • A tagging system that simplifies access to menu entries in the menu tree.
  • Support for user defined tags that depend on the toplevel window context.
  • A simplified and uniform interface for all callback commands.
  • Namespace support for all callback commands so callback commands can be easily grouped into namespaces.
  • Support for hiding and exposing menus on the menubar.
  • A simplified method for creating radiobutton groups.
  • Automatic management of state variables for checkbuttons and radiobuttons.
  • Scope control for the state variables of checkbuttons and radiobuttons.
  • Tear-off menu management that ensures only one tearoff menu is created.
  • Support for dynamic menu extension to simplify the creation of recent document menus.
  • Support for saving and restoring dynamic menu extensions.

ngl, that list ate. periodt. πŸ’…


🌈 TERMINOLOGY 🌈

The visible rendering of a menubar in a toplevel window is a horizontal group of cascading Tk menus.

A menu is an ordered list of items that is rendered vertically. Menus are not visible until a user performs some action (normally a <ButtonPress-1> event). A menu may contain any number of child menus that are rendered as cascading menus. Cascading menus are rendered next to the parent menu when they are activated.

MENU ENTRY

A menu contains an ordered list of items called entries. Menu entries have a type and the menubar class supports the following 6 entry types: Command, Checkbutton, Radiobutton, Separator, Group and Menu.

ENTRY LABEL

Each menu entry has a visible string that is called the entry label.

TAG

A tag is a name normally used to refer to an item in a menu tree. A tag name is an alphanumeric character string that may include the underscore character. Menu tree tags are defined for all nodes and leafs in a menu tree. This provides a flat abstraction of the tree and simplifies item referencing in menubar methods. Without this abstraction it would be necessary to reference menu elements using a tree path which could change at run-time. The menubar class also has a method that can create a user defined tag. User defined tags store values that change based on the currently active toplevel window. User defined tags can be used to store widget pathnames used by callback code so that output can be routed to the appropriate toplevel window. literally the main character energy of menu references, fr fr πŸ¦‹

πŸ› οΈ METHODS πŸ› οΈ

🧚 mBarInst define body

Okay bestie, this one compiles body into a tree of menu entries that literally define the visual layout of the menubar. The body argument describes the layout using the syntax below, and every element of that syntax is explained right after. πŸ’–

body == definitions

definitions    ::= { <ignore> | <definition> | <definition> <definitions> }
ignore         ::= { <nl> | <white-space> <nl> | # <comment> <nl> }
definition     ::= { <command> | <checkbutton> | <radiobutton> | <separator> | <group> | <menu> }
command        ::= <label> C <tag> <nl>
checkbutton    ::= <label> X<scope> { <tag> | <tag>+ } <nl>
radiobutton    ::= <label> R<scope> { <tag> | <tag>+ } <nl>
separator      ::= <stext> S <tag> <nl>
group          ::= <dummy> G <tag> <nl>
menu           ::= <label> { M:<tag> | M:<tag>+ } <nl> <definitions>
stext          ::= '--' | <label>
scope          ::= '' | '@' | '='

πŸ’… C β€” Command

The C type entry is the most common type of entry, periodt. This entry executes a command when it is invoked. Simple, iconic, does exactly what it says on the tin. ✨

πŸŽ€ X β€” Checkbutton

A X type entry behaves much like a Tk checkbutton widget. When it is invoked it toggles back and forth between a selected and deselected state. The value of a checkbutton is a boolean (i.e. 1 or 0). By default all checkbuttons are deselected. If you want the checkbutton to be initially selected then include a trailing plus (+) with the tag name. See SCOPE CONTROL below for a description of the scope indicator. πŸ¦‹

🌸 R β€” Radiobutton

A R type menu entry behaves much like a Tk radiobutton widget. Each radiobutton entry is a member of a radiobutton group that controls the behavior of the radiobuttons in the group. All radiobuttons in a group are given the same tag name. In the example below Red, Green and Blue all have the same tag and are therefore all in the same radiobutton group. A trailing plus (+) on the tag name of a radiobutton entry will cause the entry to be the initially selected entry. See SCOPE CONTROL below for a description of the scope indicator. πŸ’–

🌈 S β€” Separator

A S type menu entry is an entry that is displayed either as a horizontal dividing line or a label. Separators are not active elements of a menu and have no associated behavior if they are invoked. If <stext> is two dashes (i.e. '--') then the separator will be displayed as a horizontal line otherwise <stext> will be displayed as a bold label surrounded by double dashes (e.g. "-- <stext> --") with a lightgray background. Lowkey decorative, highkey useful. πŸŽ€

πŸ‘‘ G β€” Command Group

The G type menu entry marks a location in the menu tree where entries can be dynamically added and removed. Menu extension can only occur at the end of a menu so G type entries must be the last item on a menu. A G type entry is rendered as a separator line. The group.<xxx> sub-commands are used to manipulate command group entries. 🫢

Bestie, please don’t forget: G entries have to be the last item on a menu. That’s not a vibe check, that’s a rule. πŸ’€

An M type entry is used to define both menubar menus and cascading menus. Menu entries are the most complicated of the 6 menu types. A menu entry is composed of three list elements. The first element of the list is its label. The second element of the list is a composite string consisting of a type identifier (M) followed by an optional tag (beginning with a ':' separator) and finally an optional plus (+) which indicates that the menu is a tear-off menu. The final element of the list is a LIST VALUE. It’s giving main character energy, honestly. πŸ’…

🫢 mBarInst install pathName body

The install method installs the menubar created with the define method into toplevel window pathName. The body argument of the command contains a tcl script which is used to initialize the installed menubar. Normally the tcl script will contain calls to various menubar methods to perform the initialization. The initialization code is only run once when the menubar is installed. The namespace in which the install method is executed becomes the default namespace for callback commands (see menu.namespace below for more details). ✨


πŸ’– METHODS - MENU.XXX πŸ’–

🌟 mBarInst menu.configure option tag-settings ?option tag-settings ...?

Configures the tags of a menubar and returns an empty string. This method provides a convenient way to configure a larger number of tags without the verbosity of using the tag.configure method. Slay, no repetitive typing era. πŸŽ€

  • option β€” Option may have any of the values accepted by the tag.configure method.
  • tag-settings β€” The tag-settings argument is a string that is converted to a list of tag-value pairs using the following syntax.

Syntax for tag-settings:

tag-settings ::= { <ignore> | <value> | <value> <tag-settings> }
ignore       ::= { <nl> | <white-space> <nl> | # <comment> <nl> }
value        ::= <tag> <option-value> <nl>

πŸ¦‹ mBarInst menu.namespace tag namespace

Change the namespace for a sub-tree of the menubar starting at entry tag. The new value will be namespace. Each entry in the menubar tree has an associated namespace which will be used for its callback procedure. The default namespace is the namespace where the install method was executed. The namespace method can be used to change the namespace that will be used for callbacks in a sub-tree of the menubar. This method can only be used in the context of an install script. Periodt. πŸ’œ

🌸 mBarInst menu.hide tag

Remove (hide) a menubar entry. When a menubar tree is defined all entries are visible by default. This method can be used to hide a menubar entry. The hide methods can be used in the context of an install script so that a menu will be initially hidden at application start up. The tag argument is the tag name of the menu to be hidden. Sneaky little menu, tucked away. πŸ™ˆ

πŸŽ€ mBarInst menu.show tag

Exposes (shows) a hidden menubar entry. When a menubar tree is defined all entries are visible by default. If a entry is hidden from the user (using the menu.hide method) then it can be exposed again using the show method. The tag argument is the tag name of the menu to be shown. Bringing it back out like the icon it is. πŸ‘‘βœ¨

✨ METHODS - TAG.XXX ✨

Okay bestie, this is the tag era of the page πŸ’… Tags are doing a lot here, so let's go one method at a time.

  • mBarInst tag.add tag value β€” adds a user-defined tag value. This method adds a new tag-value pair to the tags defined for a menubar. User-defined tags are not the same as the tags created by the define method. The tag.add method can only be used in an install script, and its value is associated with the toplevel where the menubar is installed. That makes the tag context sensitive, so callback code that queries the tag value will receive a value associated with the window that performed the callback. Periodt. πŸ’–
  • mBarInst tag.configure pathName tag ?option value ...option value? β€” given the pathName of a toplevel window and a tag, this method configures the menu entry associated with the tag and returns an empty string. Slay.

πŸ’… Standard Options πŸ’…

These options are the same as those described for menu entries in the Tk menu documentation:

  • -activebackground
  • -activeforeground
  • -background
  • -bitmap
  • -columnbreak
  • -compound
  • -font
  • -foreground
  • -hidemargin
  • -image
  • -indicatoron
  • -label
  • -selectcolor
  • -selectimage
  • -state

πŸŽ€ Class Specific Options πŸŽ€

  • -bind {uline accel sequence} β€” the value of the -bind option is a three-element list, and the values are:
    • uline β€” an integer index of a character to underline in the entry. This value performs the same function as the Tk menu -underline option. If this value is an empty string, then no underlining is performed.
    • accel β€” a string to display at the right side of the menu entry. The string normally describes an accelerator keystroke sequence that may be typed to invoke the same function as the menu entry. This value performs the same function as the Tk menu -accelerator option. If this value is an empty string, then no accelerator is displayed.
    • sequence β€” a bind sequence that will cause the entry's associated command to fire.
  • -command cmdprefix β€” the value of the -command option is a command prefix that is evaluated when the menu entry is invoked. By default the callback is evaluated in the namespace where the install method was executed. Additional values are appended to the cmdprefix and are thus passed to the callback command as arguments. These additional arguments are described in the list below:
    • command entry
      1. The pathname of the toplevel window that invoked the callback.
    • checkbutton entry
      1. The pathname of the toplevel window that invoked the callback.
      2. The checkbutton's tag name.
      3. The new value for the checkbutton.
    • radiobutton entry
      1. The pathname of the toplevel window that invoked the callback.
      2. The radiobutton's tag name.
      3. The label of the button that was selected.
    • group entry
      1. The pathname of the toplevel window that invoked the callback.
  • mBarInst tag.cget pathName tag ?option? β€” returns the value of the configuration option given by option, or the value of a user-defined tag. The option argument may be any of the options accepted by the tag.configure method for the tag type. User-defined tags are queried without an option value. Iconic. ✨

🌸 METHODS - GROUP.XXX 🌸

Group chat, but make it menu entries. Let's get into it 🫢

  • mBarInst group.add tag label ?cmd? ?accel? ?sequence? ?state? β€” adds a command to the group with tag name tag. This method appends a new command entry to the end of a command group. The order of the arguments is fixed, but arguments to the right can be ignored. The arguments have these meanings:
    • tag (string) β€” the tag name of the command group.
    • label (string) β€” the displayed label for the menu entry.
    • cmd (string) β€” a command prefix that will be used for the callback command.
    • accel (string) β€” an accelerator string that will be displayed next to the entry label.
    • sequence (string) β€” a bind sequence that will be bound to the callback command.
    • state (enum) β€” sets the active state of the command. One of: normal, disabled, active.
  • mBarInst group.delete tag label β€” deletes a command from a group with tag name tag. This method deletes command label from a command group.
  • mBarInst group.move direction tag label β€” changes the position of an entry in a group with tag name tag. The direction argument is the direction ('up' or 'down') the entry will be moved. The entry that is moved has the name label.
  • mBarInst group.configure tag label ?option value ...option value? β€” configures the options of an entry in the command group with tag name tag. This method is similar to the tag.configure method, except that it works on entries in a command group. See the documentation for the tag.configure method above for more details on command entry options.
  • mBarInst group.serialize tag β€” returns a string serialization of the entries in a command group. The argument tag is the tag name for the group that is to be serialized. The resulting serialization is a list containing three elements: (1) the tag name of the group, (2) a dictionary containing group-level options, and (3) a list of zero or more similar three-element lists that describe the entries in the group.
  • mBarInst group.deserialize tag stream β€” replaces the contents of group tag with the commands defined in the serialization stream. The original contents of the group are lost. No cap, gone gone. πŸ’€

πŸ¦‹ METHODS - NOTEBOOK.XXX πŸ¦‹

Notebook tabs need their little state babysitters, and that is literally what these are for πŸŽ€

  • mBarInst notebook.addTabStore pathname β€” this method should be used in code that creates a new notebook tab. Execution of this method will cause state storage to be allocated for the new notebook tab. The pathname for the notebook tab is passed as an argument to the method.
  • mBarInst notebook.deleteTabStore pathname β€” this command deallocates the state store for a notebook tab. The pathname for the notebook tab is passed as an argument to the method.
  • mBarInst notebook.setTabValue pathname tag β€” this method should be used in the callback for menubar checkbuttons or radiobuttons that have notebook tab scope control. When this method is executed, it will move the value associated with tag into the tab store for the tab identified by pathname.
  • mBarInst notebook.restoreTabValues pathname β€” this method should be placed in a bind script that is triggered by a notebook's <<NotebookTabChanged>> event. Obsessed with a well-timed event binding, honestly. πŸ¦‹

πŸ‘‘ SCOPE CONTROL πŸ‘‘

By default, a menubar instance looks the same in all installed toplevel windows. As changes are made to one instance of a menubar, all the other instances are immediately updated. This means the internal state of all the menu entries for the instances are synchronized. This behavior is called global scope control of the menubar state. Very main character energy: one state, all windows. πŸ‘‘

The menubar class allows finer scope control on check and radio buttons. The scope of these entry types can be modified by adding a modifier character to their type character. Two modifier characters are supported, and here's the scoop:

  • Local scope character: @ β€” when the local scope character (@) is added to the definition of a button, the button is given a new variable for each installed toplevel window. This has the effect of making the button's state local to the window (i.e. local scope). An example use case for this behavior might be a status bar that can be toggled on and off by a checkbutton. The developer may want to allow the user to control the visibility of the status bar on a per-window basis. In this case, a local modifier would be added to the status bar selector so the callback code would receive an appropriate value based on the current toplevel window.
  • Notebook tab scope character: = β€” the notebook tab scope character (=) is similar in effect to the local scope character, but it allows a notebook tab selection to also manage the state of a button. Adding the notebook tab scope modifier enables notebook tab scope control, but the developer must then make use of the notebook.xxxx sub-commands to actively manage state values as tabs are added, deleted, and selected. That's the whole vibe πŸ’…

πŸŽ€ EXAMPLE πŸŽ€

okay bestie, this is the whole vibe in one go β€” a full working app, no cap. read it, run it, live it:

package require Tcl
package require Tk
package require menubar

set tout [text .t -width 25 -height 12]
pack ${tout} -expand 1 -fill both
set mbar [menubar new \
    -borderwidth 4 \
    -relief groove  \
    -foreground black \
    -background tan \
    ]
${mbar} define {
    File M:file {
        Exit                 C      exit
    }
    Edit M:items+ {
    #   Label               Type    Tag Name(s)
    #   -----------------   ----    ---------
        "Cut"               C       cut
        "Copy"              C       copy
        "Paste"             C       paste
        --                  S       s2
        "Options" M:opts {
            "CheckList" M:chx+ {
                Coffee      X       coffee+
                Donut       X       donut
                Eggs        X       eggs
                }
            "RadioButtons" M:btn+ {
                "Red"       R       color
                "Green"     R       color+
                "Blue"      R       color
                }
        }
    }
    Help M:help {
        About               C       about
    }
}
${mbar} install . {
    ${mbar} tag.add tout ${tout}
    ${mbar} menu.configure -command {
        # file menu
        exit            {Exit}
        # Item menu
        cut             {CB Edit cut}
        copy            {CB Edit copy}
        paste           {CB Edit paste}
        # boolean menu
        coffee          {CB CheckButton}
        donut           {CB CheckButton}
        eggs            {CB CheckButton}
        # radio menu
        color           {CB RadioButton}
        # Help menu
        about           {CB About}
    } -bind {
        exit        {1 Cntl+Q  Control-Key-q}
        cut         {2 Cntl+X  Control-Key-x}
        copy        {0 Cntl+C  Control-Key-c}
        paste       {0 Cntl+V  Control-Key-v}
        coffee      {0 Cntl+A  Control-Key-a}
        donut       {0 Cntl+B  Control-Key-b}
        eggs        {0 Cntl+C  Control-Key-c}
        about       0
    } -background {
        exit red
    } -foreground {
        exit white
    }
}
proc pout { txt } {
    global mbar
    set tout [${mbar} tag.cget . tout]
    ${tout} insert end "${txt}\n"
}
proc Exit { args } {
    puts "Goodbye"
    exit
}
proc CB { args } {
    set alist [lassign ${args} cmd]
    pout "${cmd}: [join ${alist} {, }]"
}
wm minsize . 300 300
wm geometry . +4+4
wm protocol . WM_DELETE_WINDOW exit
wm title . "Example"
wm focusmodel . active
pout "Example started ..."

no literally, that's the whole flex πŸ’… the define block sets up the whole menu tree, install wires it into ., the -command map points every tag at a proc, the -bind map slaps accelerators on things (look at how exit gets 1 Cntl+Q Control-Key-q and cut gets 2 Cntl+X Control-Key-x β€” those leading numbers are the modifiers and the second field is the actual binding, iykyk), coffee/donut/eggs get no modifier (0 Cntl+A-style entries) and about is just plain 0 with nothing else β€” and then -background/-foreground recolour exit red-on-white because somebody wanted the quit button to look like a whole moment. also pout grabs the text widget via tag.cget . tout and dumps lines into it, CB prints "${cmd}: [join ${alist} {, }]", and Exit says Goodbye and bails. window gets an wm minsize . 300 300, wm geometry . +4+4, a WM_DELETE_WINDOW protocol hooked to exit, title Example, wm focusmodel . active, and a little pout "Example started ..." so you know it's alive πŸ¦‹


πŸ’€ CAVEATS πŸ’€

real talk: this implementation uses TclOO, so it requires 8.6 β€” no 8.5, no exceptions, don't even try. and the code has been tested on Windows (Vista), Linux and OSX (10.4). Vista and OSX 10.4, iconic era honestly 😭


🌈 REFERENCES 🌈

see also:

like, go read the Tk menu page and that wiki page that makes menubar objects 🫢


πŸ› BUGS, IDEAS, FEEDBACK πŸ›

ngl, this document β€” and the package it describes β€” will undoubtedly contain bugs and other problems. pls report such in the category menubar of the Tklib Trackers at [http://core.tcl.tk/tklib/reportlist]. and also pls report any ideas for enhancements you may have for either the package and/or the documentation β€” they're begging, bestie, don't leave them hanging πŸ™ˆ


Copyright (c) 2009 Tom Krehbiel <krehbiel.tom@gmail.com> All rights reserved.


and that's the whole page, bestie!! ✨ shoutout to tklib version 0.5, this gorgeous little menubar(n), stamped with that menubar(n) page header energy β€” go forth and build menus that eat πŸ’…πŸ’–

πŸ“¦ where this page comes from
  • alpine 3.24: tk-lib-doc 0.7-r0 Β· TCL
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms