📜 ⬆️ ⬇️

Using dictionaries in tcl

Greetings, Habra! % username, you probably heard about such a language as tcl and its graphic toolkit tk. The language is particularly flexible (in my humble opinion). While there is not much time to write about the "cloud" development, I decided to write a mini-article / mini-lesson about one of the features of the wonderful language tcl - dictionaries (and, I can not recall them in the book "Practical Tcl / TK programming", perhaps just read the old version). The most complete description of this data type,% username, you can find by reference .

A bit of theory - a dictionary in tcl is a type of data that allows you to store complex ordered values ​​of the type "key-value", and with the ability to branch the tree itself. In other words, a single key (for example, a record ID) may have more than one value, but several more keys with values. It looks like this in the tcl syntax:
dict set nonUserSettings 0 title "myProgram" dict set nonUserSettings 0 minWidth 800 dict set nonUserSettings 0 minHeight 600 dict set nonUserSettings 0 resizableX 1 dict set nonUserSettings 0 resizableY 1 

What does this code do? It's simple - he creates a dictionary programSettings, which has the attributes title, minWidth, minHeight, resizableX, resizableY. Moreover, due to the ID of the element in the dictionary, we can rub settings for other root windows of programs (this may be necessary if you plan to do multi-window
interface).

Access to the value from the dictionary can be obtained by means of the following command:
 dict get <-> <> 

Let's draw the Tk window using our dictionary. Normal code would look like this:
 wm title . "myProgram" wm resizable . 1 1 wm minsize . 800 600 

Our code will look like this:
 wm title . [dict get $nonUserSettings 0 "title"] wm resizable . [dict get $nonUserSettings 0 "resizableX"] [dict get $nonUserSettings 0 "resizableY"] wm minsize . [dict get $nonUserSettings 0 "minWidth"] [dict get $nonUserSettings 0 "minHeight"] 

What will it give us? In essence, dictionaries (as well as all the data in tcl) are mutable. Consequently, can be redefined. Thus, we get a window that changes when you redefine the value obtained from the dictionary. In this case, restarting the program is not required. In other words - your GUI settings will be picked up dynamically. But, all this can be easily implemented through the list. Then why do we need to use a dictionary. Well, firstly - using the dictionary will make the program more readable, its data - more systematic (in fact, you keep some kind of database table in the code). And on the other ... now show.

Suppose we need to make the usual top menu. As a widget - it has its own name, as well as the option tearOff. To store the settings, create another
vocabulary:
 dict set menuBarSettings 0 name mainMenuBar dict set menuBarSettings 0 tearOff 1 

Data about the type of drop-down menu from the menu bar will add immediately:
 option add *tearOff [dict get $menu-settings 0 "tearOff"] 

Also, suppose we want to give the user the ability to enable and disable the top menu:
 dict set userSettings 0 menuBar true 

But with the rendering let's wait a little. Describing the entire GUI manually does not make much sense, because we have in the arsenal a very powerful tool - an iterative search of the dictionary for keys and parameters. For the menu of menu titles we create a dictionary:
 dict set menuBarItems_ZeroLevel 0 name connectionItem dict set menuBarItems_ZeroLevel 0 text_item "Connection" dict set menuBarItems_ZeroLevel 1 name helpItem dict set menuBarItems_ZeroLevel 1 text_item "Help" 

Now we will create a dictionary in which the first level will be stored by me (the parent parameter will denote the id of the menu header to which the first level is attached):
 dict set menuBarItems_FirstLevel 0 parent 0 dict set menuBarItems_FirstLevel 0 label "Open" dict set menuBarItems_FirstLevel 0 command NONE dict set menuBarItems_FirstLevel 1 parent 0 dict set menuBarItems_FirstLevel 1 label "Editt" dict set menuBarItems_FirstLevel 1 command NONE dict set menuBarItems_FirstLevel 2 parent 0 dict set menuBarItems_FirstLevel 2 label "Exit" dict set menuBarItems_FirstLevel 2 command { exit; } dict set menuBarItems_FirstLevel 3 parent 1 dict set menuBarItems_FirstLevel 3 label "About" dict set menuBarItems_FirstLevel 3 command NONE dict set menuBarItems_FirstLevel 4 parent 1 dict set menuBarItems_FirstLevel 4 label "Help" dict set menuBarItems_FirstLevel 4 command NONE 

The standard menu syntax will not be disassembled, it can be viewed in any tutorial. It is better to go straight to the menu “drawing” algorithm:
 #  ,   ""    proc assembleMyMenu {} { # ,       ,             global userSettings global menuBarSettings global menuBarItems_ZeroLevel global menuBarItems_FirstLevel # ,        if {[dict get $userSettings 0 "menuBar"]==true} { # ,  , : #       ( ,       ""      menu .[dict get $menuBarSettings 0 "name"] #          . config -menu .[dict get $menuBarSettings 0 "name"] #   .         dict for {id info} $menuBarItems_ZeroLevel { # info -        . ,   id-      ,     with     : dict with info { #        name  menu-bar-items       menu-settings: menu .[dict get $menuBarSettings 0 "name"].$name #    .[dict get $menuBarSettings 0 "name"] add cascade -label $text_item -menu .[dict get $menuBarSettings 0 "name"].$name #        ,     menu-bar-items_first-level dict for {iter data} $menuBarItems_FirstLevel { dict with data { #      ,   - : if {$id==$parent} { #    -     .[dict get $menuBarSettings 0 "name"].$name add command -label $label -command $command } } } } } } } 

The full code of our program:
')
 #Require main packages for work package require Tk # Data for non user settings dict set nonUserSettings 0 title "myPrograms" dict set nonUserSettings 0 minWidth 800 dict set nonUserSettings 0 minHeight 600 dict set nonUserSettings 0 resizableX 1 dict set nonUserSettings 0 resizableY 1 # Data for user settings dict set userSettings 0 menuBar true # Data for biuld menubar dict set menuBarSettings 0 name mainMenuBar dict set menuBarSettings 0 tearOff 1 # Data for 0-level menu dict set menuBarItems_ZeroLevel 0 name connectionItem dict set menuBarItems_ZeroLevel 0 text_item "Connection" dict set menuBarItems_ZeroLevel 1 name helpItem dict set menuBarItems_ZeroLevel 1 text_item "Help" # Data for 1-level menu dict set menuBarItems_FirstLevel 0 parent 0 dict set menuBarItems_FirstLevel 0 label "LogIn" dict set menuBarItems_FirstLevel 0 command NONE dict set menuBarItems_FirstLevel 1 parent 0 dict set menuBarItems_FirstLevel 1 label "LogOut" dict set menuBarItems_FirstLevel 1 command NONE dict set menuBarItems_FirstLevel 2 parent 0 dict set menuBarItems_FirstLevel 2 label "Exit" dict set menuBarItems_FirstLevel 2 command { exit; } dict set menuBarItems_FirstLevel 3 parent 1 dict set menuBarItems_FirstLevel 3 label "About" dict set menuBarItems_FirstLevel 3 command NONE dict set menuBarItems_FirstLevel 4 parent 1 dict set menuBarItems_FirstLevel 4 label "Help" dict set menuBarItems_FirstLevel 4 command NONE # Procedure for builing menu bar proc assembleMyMenu {} { global userSettings global menuBarSettings global menuBarItems_ZeroLevel global menuBarItems_FirstLevel if {[dict get $userSettings 0 "menuBar"]==true} { menu .[dict get $menuBarSettings 0 "name"] . config -menu .[dict get $menuBarSettings 0 "name"] dict for {id info} $menuBarItems_ZeroLevel { dict with info { menu .[dict get $menuBarSettings 0 "name"].$name .[dict get $menuBarSettings 0 "name"] add cascade -label $text_item -menu .[dict get $menuBarSettings 0 "name"].$name dict for {iter data} $menuBarItems_FirstLevel { dict with data { if {$id==$parent} { .[dict get $menuBarSettings 0 "name"].$name add command -label $label -command $command } } } } } } } # Main programm logic # Window Manager main settings wm title . [dict get $nonUserSettings 0 "title"] wm resizable . [dict get $nonUserSettings 0 "resizableX"] [dict get $nonUserSettings 0 "resizableY"] wm minsize . [dict get $nonUserSettings 0 "minWidth"] [dict get $nonUserSettings 0 "minHeight"] option add *tearOff [dict get $menuBarSettings 0 "tearOff"] assembleMyMenu 


I hope the lesson / article was helpful. Have a nice dive into the tcl / tk addict code!

Source: https://habr.com/ru/post/174243/


All Articles