Tcl/Tk

Григорий Строкин

Дата создания: 3.06.99
Дата последнего изменения: 13.06.99

Источники Нечто про tcl/tk по-русски. http://www.florin.ru/koi/tcl-tk/I_gu10.htm John K. Ousterhout. Tcl and the Tk Toolkit. Addison-Wesley, 1994 (?) (Ousterhout -- это создатель Tcl/Tk) Draft 8/12/93 :(( Доступен online :)) в PostScript, 390 с. Написан в эпоху Tk 3.2 (а сейчас Tk 8.1) В 4 частях: [0. Introduction. An overview of Tcl and Tk.] 1. The Tcl language 2. Writing scripts for Tk 3. Writing Tcl Applications in C (это я не читал пока) 4. Tk's C interfaces (это тоже) Brent Welch. Practical programming in Tcl and Tk. Prentice Hall, 1995. Draft от 13 янв 1995, updated for Tcl 7.4 and Tk 4.0 Доступен в online, PostScript, 420 с. Пока прочитал Introduction.


ЦИТАТЫ http://www.techweb.com/se/directlink.cgi?EET19980713S0028 Ousterhout developed Tcl while a professor at UC Berkeley in the mid-1980s. The idea came out of his work with IC design tools. "We found that every program we built needed a command language," he said. "I got the idea that maybe I could build a reusable command language, where the interpreter is a library package you could use in lots of different programs for different purposes." The salacious truth of the scripting paradigm shift to Tcl/Tk and Python http://www.infoworld.com/cgi-bin/displayNew.pl?/petrel/980928np.htm Look for other scripting languages to get a boost soon, as PCs get more robust and invade the enterprise infrastructure where the advanced workstations and minicomputers once ruled. Why? As much as some people would like to think PCs can replace big machines without having to resort to a command-line paradigm, I'm here to tell you it just ain't possible. GUIs are by nature general purpose interfaces. They're great for introducing simplicity and consistency to applications that perform a predictable set of individual tasks. But they're really lousy at handling huge, complicated, and unpredictable administrative operations that step outside the nice, neat boundaries of predefined groups of users or files. John K. Ousterhout. Tcl and the Tk Toolkit Although Tcl provides a full set of programming features such as variables, loops, and procedures, it is not intended to be a stand-alone programming environment. Tcl is intended to be used as part of applications that provide their own Tcl commands in addi tion to those in the Tcl core. The application-specific commands provide interesting prim itives and Tcl is used to assemble the primitives into useful functions. Tcl by itself isn't very interesting and it is hard to motivate all of Tcl's facilities until you have seen some interesting application-specific commands to use them with. ОБОЗНАЧЕНИЯ Процент (%) иногда ставится перед командой, для отличения ее от результата выполнения команды. Вопросительные знаки с двух сторон (?пример?) обозначают факультативные аргументы. Традиционно для этого используются квадратные скобки, но в Tcl они имеют особое значение. КОНСПЕКТ. ЧАСТЬ 1: TCL Автор Tcl говорит, что Tcl произносится как 'tickle'. Если вам нравится, можете тоже так произносить. Заявление: Единственный тип данных -- строка. Далее сразу говорится, что существует три формы строк -- команды, выражения и списки. В дальнейшем выясняется, что существуют массивы, а также ошибка "variable isn't array" и даже "variable is array" (!) Мои первые команды: % set a 10 # print?display?write?show? a ? нет, ничего не подходит % echo $a 10 % set 20 30 % echo $20 30 # да уж.... Если команда неопределена в tcl, осуществляется поиск executable в $PATH, точно так же, как в shell (!) т.е. можно % ls % /bin/ls и т. п. Если команда x неизвестна и такой программы нет в $PATH, вызывается % unknown x Которая пытается найти какую-нибудь команду, начинающуюся с x (а если не находит, выдает сообщение об ошибке) Это позволяет использовать сокращенные имена для стандартных команд, но так делать не рекомендуется. В качестве кавычек (=группирования) используются "" и {}. Фигурные скобки {} -- аналог одинарных кавычек в shell и перл, а кроме того, разрешено вложение: { строка {подстрока} } -- аналог "строка \"подстрока\"" (ср. различие между backquotes и $() в bash) Как внутри {}, так и внутри "" разрешены newlines. Можно включить в аргумент пробел и без использования кавычек: % set a hi\ there Квадратные скобки [] -- аналог backquotes в shell. Комментарии (#) считаются командами, поэтому нельзя команда # комментарий, надо команда; # комментарий и поэтому можно: # комментарий \ продолжение комментария СИНТАКСИС Синтаксиса нет по той причине, что существует однозначное соответствие между первым словом команды и функцией на Си, ее исполняющей, и этой функции передаются все остальные слова (как строки). Подходик... Исключение составляют widget-ы, которые, надо думать, все связаны с одной и той же Си-функцией, так как при создании новго widget-а создается и омонимичная команда, посволяющая, например, писать .widget configure. Зарезервированных слов тоже нет. ПЕРЕМЕННЫЕ Хотя существует только один тип данных, типов переменных два -- скалярные переменные и ассоциативные массивы. Значение переменной -- $var. Если надо получить значение по имени переменной, использовать set с одним аргументом: [ set a ] _идентично_ $a. Если написать: set a b set b 10 set $a 20 echo $b получим 20, так как $a раскрывается в имя переменной b. Идентификаторы могут начинаться с цифры, так что % set 10 20 % echo $10 20 Могут начинаться и с чего угодно, тогда надо делать ${var}: % set ,.+ abc % echo ${,.+} abc Удалить переменную: % unset var Это требуется, если переменная была скалярной, а мы захотели массив с тем же именем, и наоборот. ВЫРАЖЕНИЯ Арифметические действия: % echo 2+3 2+3 % expr 2+3 5 Очень по-шелловски... expr-у пофигу, пишем мы 2+3, 2 + 3 или 2+ 3. Может сравнивать строки, но нельзя: expr $s1 == $s2 а можно expr {$s1 == $s2} Арифметические операции: incr var ?increment? ;# деструктивная это короче чем set var [expr $var+1] РАБОТА СО СТРОКАМИ append s s1 s2 ... ;# деструктивная; ср. strcat в Си Превращение строк в списки и обратно: Разбиение строки split s ?delim? Если delim нет, подразумевается пробел. Если delim=="", разбивается посимвольно. Объединение строк join s ?delim? Работа со строками, содержащими двоичные данные: команда binary (не смотрел). Очень похожа на perl pack/unpack. Команда string Длина строки: string length s Сравнение: string equal s1 s2 ;# только начиная с 8.1 ! string compare s1 s2 Сопоставление с glob-style wildcards: string match wildcard s string match -nocase wildcard s n-ный символ строки: string s n Подстрока оттуда-то до туда-то % string range "abcdefgh" 1 6 bcdefg Аналог strstr, но возвращает позицию: % string first "def" "abcdefg abcdefg" 3 (а если нету, то -1) А так самый последний: % string last "def" "abcdefg abcdefg" 11 Перевести в большие/маленькие буквы: string toupper "Tcl 8.1 работает с русскими буквами без всяких настроек" string tolower ... Удалить начальные и конечные пробелы или табуляции: string trim " строка " Удалить другие символы в начале и конце: string trim "***__строка__***" "*_" Только в конце или только в начале: string trimleft ... string trimright ... Аналог sscanf: scan s format var1 var2 ... Напр. scan "10 20 abc" "%i %i %s" i n s Аналог sprintf: % format abc abc % format "Dear %s and %s!" ladies gentlemen Dear ladies and gentlemen! Регулярные выражения Те самые, что в Tkinter.Text.search (похожи на egrep) В Tcl 8.1 используются НОВЫЕ регулярные выражения, включающие классы символов a-la перл типа \d % regexp {[0-9]+} {I have 50 bananas} # просто проверка, есть ли 1 % regexp {[0-9]+} {I have 50 bananas} s # в s запишется совпадение 1 % echo $s 50 % regexp {([0-9]+)-([0-9]+)-([0-9]+)} {Наш телефон -- 939-26-01} s x y z 1 % echo $s 939-26-01 % echo $x$y$z 9392601 У regexp есть опции -nocase и -indices. В этом случае вместо совпадений возвращаются пары {pos len} Замена: regsub regexp $src replace_string dst_var По умолчанию заменяет первое вхождение; есть опции -all и -nocase. В replace_string разрешено &, \0 (эквивалентно &) и \1, \2, ... Эквивалент списка: Просто строка, где элементы разделены пробелами (и, может быть, сгруппированы фигурными скобками) Фигурные скобки создают вложенный список. Работа со списками: Доступ к элементу: % lindex {10 20 30 40} 2 30 % foreach i { 10 20 30 } { echo [expr $i*$i] } 100 400 900 % lrange {a b c d e f} 2 4 c d e % llength {abc def ghi} 3 % lsort {p h i l o s o p h y} h h i l o o p p s y lsort имеет опции: -ascii -integer -real -decreasing -index -dictionary -command. -dictionary -- не различать большие и маленькие буквы % set a {abc def} % set b {ghi jkl} % concat $a $b abc def ghi jkl % set a {10 20 30} % lappend a 40 # деструктивная! % echo $a 10 20 30 40 % linsert {10 20 30 40} 2 25 26 # недеструктивная 10 20 25 26 30 40 % list "a" "a b c" "b" ;# добавляет { } для вложенных списоков a {a b c} b % lreplace {a b c d e f g h i j} 2 4 x y # заменить эл. 2-4 на x y a b x y f g h i j Поиск: lsearch; есть опции -exact, -glob, -regexp % lsearch { a b c d e f g } c 2 % lsearch -regexp { aba aca ada aga } .d. 2 МАССИВЫ Ассоциативные. % set a(1) 10 % set uid(grg) 1001 # так нельзя: echo ${uid}(grg) Так что массивами могут быть только переменные с "нормальными" идентификаторами. Работа с массивами: команда array функция массив [аргументы] с функциями anymore, donesearch, exists, get, names, nextelement, set, size, or startsearch Создать ассоциативный массив из пар (key, value): % array set z {grg 1001 ic 1002} % echo $z(grg) 1001 % array names z ic grg % array size z 2 % array exists z # существования массива с данным именем 1 % array get z % получить пары (key, value) ic 1002 grg 1001 Прохождение по всем элементам: % set handle [array startsearch z ] # начать; напоминает {open,read}dir() % array nextelement z $handle # получить очередной ключ ic % array anymore z $handle # есть ли еще ключи? 1 % array nextelement z $handle grg % array anymore z $handle 0 % array donesearch z $handle # зачем? ЭКВИВАЛЕНТЫ FLOW CONTROL Простой цикл: for {set i 0} { $i < 10 } { set i [expr $i + 1]} {echo $i} Не такой уж он и простой :) while {} {} if {} then {} ?else {}? if {} {} ?{}? if {} elseif {} elseif ... if {} else {} ;# эквивалент unless в перле switch отличается от switch в Cи: switch $var value1 {action1} value2 {action2} ... или switch $var { value1 {action1} value2 {action2} ... } Выбирается только одна альтернатива, так что break не нужен. Кроме того, switch возвращает результат вычисления выражения actionN. Кроме того, switch имеет опции -exact, -glob, -regexp ПО УМОЛЧАНИЮ -glob, поэтому valueN на самом деле не value, а pattern. Несколько шаблонов пишутся так: switch $v value1 - value2 - value3 {action1} value4 {action2} Текст условий передается вроде как expr-у. Условия для циклов надо всегда заключать в {}: если их заключить, скажем, в кавычки, то условия будет вычеслено один раз в начале цикла, скажем $i<$n даст 1, и цикл будет бесконечным. ДРУГИЕ КОМАНДЫ Аналог at: after 1000 puts "Вот и прошло 1000 мс" interp Что? exec Выполняет программу и возвращает ее вывод т. е. нечто вроде комбинации popen и system Не использует shell, надо думать, потому что маски типа * нельзя, надо glob Если же надо, чтобы выводил на stdout, exec <@stdin >@stdout command Есть опция -keepnewline Можно делать exec command & для выполнения в фоновом режиме, тогда exec возвращает pid задачи, а не ее вывод pid $filehanle Если $filehandle -- pipe, возвратить pid этого процесса clock Текущее время clock seconds clock clicks Традиционное представление времени: % clock format [clock seconds] Mon Jun 07 00:50:28 MSD 1999 ВВОД/ВЫВОД Положить строку на stdout, добавив newline: puts "строка" puts stdout "строка" system с возможностями popen: output = exec "command" exec >@stdout "command" Файлы. Открыть для записи: set f [open "file" w] puts $f "Пишем" close $f Режим для open: либо как в Cи fopen: w, r, a, w+, r+, a+ либо как в Си open, без O_: RDONLY, CREAT и др. (man open) Имя файла для open: если первый символ "|", открывается pipe (ср. перл). но последним "|" делать нельзя (режим указывать через w или r) Для чтения: set f [open "file" r] while {![eof $f]} {puts "прочитали '[gets $f]'"} close $f Вместо set s [gets $f] можно gets $f s В случае eof gets возвращает пустую строку, поэтому отличить eof от действительно пустой строки нельзя. Прочитать все содержимое файла: set text [read $f] То же, убрав конечный newline: read -nonewline ... Прочитать n байт: read $f n Позиция в файле: tell $f seek $f pos seek $f pos "start" seek $f pos "current" seek $f pos "end" А также: flush Команда file: file option filename ... Информация о файле: size, mtime, atime exists, isfile, isdirectory, executable, readable, writable stat, lstat: Все непросто. Надо: % file stat "file" array_var % array names array_var mtime atime gid nlink mode type ctime uid ino size dev readlink (кстати, у меняx есть /usr/local/bin/readlink) owned: является ли текущий пользователь вледельцем % if {[file owned "file"]} {puts "Наш файл"} attributes: % file attributes jaa2 -group users -owner grg -permissions 00644 type: возвращает "file", "link" и др. Операции над файлами: copy, delete, mkdir, rename Работа с именами файлов: nativename: % file nativename "file" file будто бы вовзращает некоторое имя, годное для передаче системному вызову в данной ОС. Вероятно, позволяет в среде M$ перевести юниксовскую запись пути в ихнюю. dirname extension tail -- аналог basename rootname -- pathname без расширения % set logname [file rootname "/home/grg/file.tex"].log /home/grg/file.log pathtype: возвращает "absolute", "relative" или "volume relative" (для M$?) volumes: % file volumes ;# без аргументов / опять-таки для M$, надо думать Операции над именами файлов: join Аналог os.path.join в питоне % file join env(HOME) share/zdatr std/ std.dtr /home/grg/share/zdatr/std/std.dtr split % file split /home/grg/share/zdatr/std/std.dtr / home grg share zdatr std std.dtr -- НЕ аналог питоновского os.path.split python>>> s.path.split('/home/grg/share/zdatr/std/std.dtr') ('/home/grg/share/zdatr/std', 'std.dtr') fileevent, fconfigure Такие команды Розетки Команда socket открывает сокет и возвращает обычный filehandle glob И в Африке, но: 1) поддерживает ~ и {}, напр ~/python/*.{py,tcl} 2) если ничто не совпало, вызывает ошибку, но можно указать опцию -nocomplain, тогда пустая строка 3) если мы хотим передать много аргументов какой-то процедуре, обрабатывающей файлы, вот это будет неправильно: process_files [glob *.txt] потому что список все txt-файлов будет передан как один аргумент. А надо: eval process_files [glob *.txt] СКРИПТЫ Загрузить файл с командами -- source filename ПРОЦЕДУРЫ Формат команды proc: proc name {arg1 arg2 ...} {action1; action2 ...} Возвращение значения -- в стиле перла и лиспа Например: % proc sum {a b} { format "%i + %i is %i" $a $b [expr $a+$b] } % echo [sum 10 20] 10 + 20 is 30 Но можно и return... return имеет опции -code (число), -errorinfo -errorcode (как ErrID в ZDATR) См. ИСКЛЮЧЕНИЯ Аргументы по умолчанию -- как в Лиспе: proc name {a b c {d default1} {e default2}} {...} Аналог &rest: proc name args {...} args будет списком. Напр: proc sum args { set r 0; foreach i $args { incr r $i } return $r } Внутри процедуры нельзя использовать обычным образом внешние команды типа /bin/echo. Надо exec? Глобальные переменные видны доступны только после определения global var Аргументы являются локальными переменными, так что если их менять, вне процедуры это заметно не будет. Если нужно эмулировать "call by reference", при вызове процедуры указывается имя переменной (т. е. без $), а в процедуре используется заумная команда upvar, которую проиллюстрируем бесполезной функцией: proc decr {var {decrement 1}} { upvar $var n set n [expr $n-$decrement] } То есть upvar отождествляет переменную n с переменной по имени, хранящемся в var, из namespace более высокого уровня. А можно по-перловски: proc decr {var {decrement 1}} { global $var set $var [expr $$var-$decrement] } Если надо передать массив, то тоже через upvar. При каждом вызове функции создается новый namespace, и получается стек namespace-ов. У upvar есть опция, позволяющая указать номер namespace-а: upvar #0 name var #0 -- namespace верхнего уровня (глобальный?) upvar -1 name var Это default. upvar -2 name var Выполнить команду в namespace-е более верхнего уровня. uplevel {action1... action2...} Тж. uplevel #0 {...} И др. Может быть использована для создания новых "управляющих структур" типа while, if и др., потому что для них не нужно создавать новый namespace. Напр. times в стиле лиспа: proc times {i n action} { upvar $i I; set I 0 while {$I<$n} { uplevel $action; incr I } } ПРЕДОПРЕДЕЛЕННЫЕ ПЕРЕМЕННЫЕ argc, argv (без $0), argv0 argv -- "список"; доступ к первому аргументу: lindex argv 0 tcl_interactive 1 или 0 $tcl_platform(platform) env % echo $env(HOME) /usr/home/grg errorCode Ну типа моих error IDs в ZDATR, но в более читаемом виде, напр. NONE # сообщения об ошибке достаточно CHILDKILLED pid sigName msg UNIX errName msg errorInfo Текст последнего сообщения об ошибке + контекст. КОДЫ ЗАВЕРШЕНИЯ И ОБРАБОТКА ИСКЛЮЧЕНИЙ Любая команда помимо возвращаемого значения устанавливает еще и код завершения. Поскольку управляющих структур как таковых в tcl нет (!), команда for, например, проверяет, не возвратила ли очередная команда код TCL_BREAK или TCL_CONTINUE. Обычно устанавливается код TCL_OK. Еще бывают коды TCL_RETURN, TCL_ERROR Команда catch обрабатывает исключения. Исключения происходят и в результате команд break и continue. catch {command} возвращает код завершения: 0 -- TCL_OK 1 -- TCL_ERROR 2 -- TCL_RETURN 3 -- TCL_BREAK 4 -- TCL_CONTINUE Чтобы получить и результат вычислений, и код возврата, надо code = catch {action} result Если code==0, то result -- результат вычислений, если code==1, то result -- сообщение об ошибке, 2 -- значение, возвращенное через return, 3 и 4 -- "" Самому вызвать исключение: error msg ?errorCode? Может вызвать только TCL_ERROR А также: return ?-code? ?-errorinfo? ?-errorcode? В качестве значения -code можно использовать как цифры, так и слова {ok error return break continue} Коды >4 могут использоваться для юзерских исключений. NAMESPACE Есть команды namespace variable Пока не смотрел. Есть так же обозначение ::identifier, т. н. fully quolified. ВОЗМОЖНОСТИ СРЕДЫ rename procname newname переименовать процедуру time command ?n? засечь время, прошедшее после выполнения команды n раз (по умолчанию 1) unknown объясняется в самом начале trace что-то про отладку Автоматическая загрузка процедур Это как в zsh, но названия процедур и файлов не обязяны совпадать: сначала делается индекс: auto_mkindex my_lib_dir *.tcl Он навсегда сохраняется в файле my_lib_dir/tclIndex После в скриптах можно: lappend auto_path my_lib_dir А потом просто вызывать нужные процедуры. По умолчанию auto_path равно напр. /usr/local/lib/tcl8.1 /usr/local/lib /usr/local/bin В случае совпадения имен процедур выбирается та, path к которой раньше встречается в auto_path, поэтому если мы хотим быть уверены, что будут вызваны именно наши процедуры, надо добавить директорию в начало auto_path set auto_path [linsert $auto_path 0 my_lib_dir] Информация о состоянии интерпретатора, namespace и др. См. также "Информация о состоянии Tk" во второй части. Команда info: Получить тело процедуры (без имени и списка аргументов): body proc_name Информация о namespace: level -- уровень вложенности текущего namespace exists "varname" procs vars locals globals Выполняемый скрипт: script Версия Tcl: % info tclverion 8.1 % info patchlevel 8.1.1 Расширение динамических библиотек: % info sharedlibextension .so (или .dll) Загруженные объектные модули: % info loaded {objeq.so Objeq} А также: hostname, nameofexecutable complete: является ли строка синтаксически правильной командой, т. е. нет ли незакрытых [ и { и т. п. (но имя команды не проверяется) РАСШИРЕНИЕ TCL С ПОМОЩЬЮ СИ Или наоборот. И то и другое предельно просто. См. tclint.c и objeq.c в директории tcl/ КОНСПЕКТ. ЧАСТЬ 2: TK Говорится, что Tk widgets воплощают в себе Motif look-and-feel. Widgets можно было бы называть графическими примитивами, но как-то длинновато :( Имена widget-ов можно рассматривать как UNIX pathnames, с тем отличием, что вместо / используется точка. Разрушение widget-а: destroy .widget ОПЦИИ, ОБЩИЕ ДЛЯ РАЗНЫХ WIDGETS RESOURCE_MANAGER Извлечение опций, указанных пользователем в ~/.Xdefaults или через xrdb Большинство опций извлекаются автоматически, напр. wish.background -- фон окна основного окна "." wish.Button.background -- фон кнопок непосредственно в гл. окне wish*Button.background -- фон всех остальных кнопок wish*background -- фон всех остальных widgets wish*Background -- любая опция КЛАССА background, т. е. не только -background, но и -insertbackground и др. wish*BorderWidth -- аналогично Это работает только если явно запущен wish! Если какой другой скрипт с perm +x, то надо его имя и писать. Если мы хотим сначала посмотреть, указал ли пользователь значение, а если не указал, использовать наше значение (отличающееся от default), надо использовать команду option get widget option_name OptionClass, напр. option get widget . background Background Если мы хотим сами установить опцию, как если бы она была прописана в Xdefaults: option add {*font} {-*-*-*-*-*-*-*-*-*-*-*-*-koi8-r} Цветовые опции -background (aka -bg) -foreground (aka -fg) -activebackground -activeforeground -selectbackground -highlightbackground -selectforeground -insertbackground -- цвет текстового курсора -disabledforeground "Рельеф" -relief flat raised (выпуклый) sunken (вдавленный) ridge (выпуклая рамка) groove (вдавленная рамка) Размер похоже, что единица по умолчанию -- символ -width -height Рамки Рамка может быть не видна, если -relief flat -borderwidth -activeborderwidth -selectborderwidth -inserborderwidth -- рамка текстового курсора -insertwidth -- общая ширина текстового курсора -padx -- задается через pack? -pady -- -- Курсоры текстовые (insertion cursors) Параметры, регулирующие мигание: -insertoffTime -insertonTime -repeatDelay -repeatInterval См. также "Цвета" и "Рамки" Рисунки (двуцветные) -bitmap -- может быть, например, у кнопки или внутри текста @файл -- хранится в файле, сгенерированном программой X11 'bitmap'; файл представляет собой программу на Си, определяющую массив. error gray25 gray50 hourglass (песочные часы) info questhead (голова с вопросом внутри) question warning Курсоры мышиные -cursor name [fgColor [bgColor]] @файл имя -- имя из файла /usr/X11R6/include/X11/cursorfont.h без XC_ напр. watch ("ждите") umbrella Выравнивание -justify (для Entry) left right center "Якоря" -anchor Напр. как расположить текст внутри кнопки (button), или фрейм (типа toolbar в xzdatr) внутри окна: center: default: вертикально по центру, горизонтально по центру n (north) вверху; [горизонтально: по центру -- default] s (south) внизу e (east) справа; [вертикально: по центру -- default] w (west) слева ne верхний правый угол sw левый нижний угол ... Цвета см. через rgb.txt или команду X11 showrgb invoke Метод widget-ов, вызывающий процедуру, указанную ранее опцией -command bind В процедуре, обрабатывающей события, последовательности %x заменяются информацией о событии, если в этой информации есть x. Напр: bind {puts "Мышь показывает на %x:%y"} Другие: %W -- имя widget-а %A -- нажатый символ %% -- если надо собственно % Интересные события: -- перетаскивание левой кнопкой -- совсем не клавиша Enter, а вход в зону мышью send Взаимодействие друг с другом программ, написанных на Tk Все очень просто. Допустим мы хотим пошутить и удалить клавиатуру у работающей программы tkcalc.tcl Пишем из нашей программы send tkcalc.tcl {pack forget .keypad } Можно использовать эту возможность для отладки или вообще написать отладчик с возможностью "Remote debugging". Если несколько экземпляров программы с одним именем, то обычно tk делает автоматически название "tkcalc.tcl #2" и т. д. Можно запустить скрипт в фоновом режиме: send -async ... Имя приложения (собственное) можно узнать как % tk appname или % winfo name . А имена всех Tk-программ, запущенных в данный момент: % winfo interps {tkcalc.tcl #2} tkcalc.tcl wish {tk #2} tk (tk и {tk #2} -- это программы на Python/Tkinter с именем по умолчанию) Говорится, что эта возможность очень опасна для людей, которые используют xhost и не используют xauth. Если X-сервер позволяет подключаться кому угодно, и у нас на нем запущена Tk-программа, мы предоставляем свой account в распоряжение кого угодно. focus Для установки фокуса просто focus .widget Если сказать focus none то клавиатурные события не будут никуда поступать, пока юзер не установит фокус мышью. Фокус по умолчанию: focus default .widget Когда окно, которое имело фокус, исчезнет, будет включен фокус по умолчанию, если он был установлен. Это полезно делать, если мы хотим, чтобы keyboard shortcuts в программе работали всегда. entry Удаление текста: .e delete 0 end scrollbar За свое расположение рядом с нужным объектом сами они не отвечают, надо pack как надо. Создание и соединение с объектом srollbar .s -command { .l yview } -orient vertical listbox .l conf -yscroll { .s set } pack .l .s -side left -fill y Если не сделать -fill, то scrollbar будет минимального размера. -orient vertical -- default Объект обычно говорит полосе прокрутки: .s set total_units window_units first last radiobutton Сложность в том, что группа таких кнопок хранит свое состояние в общей переменной, но сами они не знают, каким значением переменной обозначать собственную нажатость. Поэтому надо указывать опцию -value, напр. pack [radiobutton .r1 -text case1 -variable r -value 1] pack [radiobutton .r2 -text case2 -variable r -value 2] pack [radiobutton .r3 -text case3 -variable r -value 3] SELECTION (aka Clipboard) Говорится, что подробно об этом можно прочитать в ICCCM, во как. Это Inter-Client Communications Convention Manual. Еще говорится, что X поддерживает несколько выделений под именами PRIMARY, SECONDARY и др., но, по-видимому, большинство программ поддерживают только PRIMARY. Получение выделения Получить выделение как текст: selection get STRING а чаще просто selection get Если владелец выделения -- наша программа, то selection own возвратит имя widget-а Получить названия видов информации о выделении: % selection get TARGETS STRING TEXT COMPOUND_TEXT LENGTH LIST_LENGTH CHARACTER_POSITION TIMESTAMP HOSTNAME IP_ADDRESS USER CLASS NAME CLIENT_WINDOW % selection get Jun 9 00:44:08 uni /kernel: pid 4696 (wish8.1), uid 1001: exited on signal 6 % selection get NAME xconsole % selection get LENGTH 0x4d Установление собственного выделения Например, мы хотим, чтобы widget класса Text мог сообщать свое FILE_NAME Тогда надо proc getfilename { i l } { global filename; return $filename } selection handle .text getfilename FILE_NAME После этого программы, которые умеют делать selection get FILE_NAME, могут этим воспользоваться. Аргументы i и l, передаваемые процедуре -- начальная позиция, с которой они хотят получить текст, и максимальная длина текста. Обычно бывает i=0, l=4000 GEOMETRY MANAGERS place Пока не был нужен Опции, общие для pack и grid -padx, -pady, -ipadx, -ipady pack Перестать обслуживать элемент: pack forget widget pack unpack widget Отличия неизвестны. В man pack для 8.0 упоминается только unpack, для 8.1 только forget, но на самом деле обе опции существуют и там и там. В книжке Ousterhout-а упоминается forget. Если мы не хотим называть .master.widget, а хотим просто .widget, можно явно указать master window: pack .widget -in .master По умолчанию элементы располагаются в том порядке, в каком для них вызывался pack. Но можно изменить порядок: pack widget1 pack widget2 pack widget3 -after widget1 pack widget4 -before widget1 Заполнить лишнее пространство: см тж. -pad, -ipad см. тж. -anchor -fill {x,y,both} -- заполнить все выделенное элементу простанство например, когда делают -side top, то по бокам может остаться свободное место, которое уже не будет использоваться для других элементов -expand 1 -- заполнить вообще все оставшееся пространство Получить список запакованных объектов: pack slaves .master Получить упаковочные опции элемента: pack info .master.widget grid -columnspan или -rowspan не увеличивают сам объект, а увеличивают выделенное ему место и центрируют посередине этого места. Чтобы увеличить объект, надо использовать -sticky (аналог одновременно -anchor и -fill для pack) Это как -anchor (см. "Опции"), причем если говорят ns -- растягивается по вертикали ew -- растягивается по горизонтали WINDOW MANAGERS Команда wm осуществляет интерфейс между программой и местным window manager-ом. К нему надо обращаться с просьбой произвести операции над toplevel windows. wm iconify .w wm deiconify .w wm title . "My Tk program" Установить пиктограмму и подпись под ней: % wm iconbitmap .w ?bitmap? % wm iconname .w "My program (minimized)" Вообще убрать окно с экрана без всяких следов, напр. для окна ".", в программе, где используются много tolplevel-windows: % wm withdraw . (обратно -- deiconify или iconify) Сказать, что такое-то окно является несамостоятельным (напр. окно диалога) и его надо минимизировать вместе с основным окном и т. п.: wm transient .dialog . ОЧЕНЬ полезная опция -- окно без рамки, для tooltips: wm overrideredirect .w 1 Сказать, что группа несамомтоятельных, но "long-lived" окон зависит от основного: foreach i {.w1 .w2 .w3 .w4} { wm group $i . } Получить информацию о "геометрии" окна: % wm geometry . 148x21+575+39 Установить "геометрию", или отдельно размер и расположение: % wm geometry . 148x21+575+39 % wm geometry . 148x21 % wm geometry . +575+39 Установить максимально допустимое уменьшение или увеличение: wm minsize . x y wm maxsize . x y Установить допустимые пределы соотношения ширины и высоты: wm aspect 1 3 4 1 Значит минимальное 1/3, максимальное 4/1 Установить обработчик сообщений "межклиентского протокола" (ICCC): % wm protocol . WM_DELETE_WINDOW { puts "Сам дурак" } Установить обработчик аварийного сохранения на случай убивания X-сервера или перезагрузки: % wm protocol . WM_SAVE_YOURSELF save_all ДИАЛОГИ Обеспечение модальности: grab .dialog tkwait window .dialog ;# ждать разрушения tkwait variable var ;# ждать изменения tkwait visibility .dialog ;# ждать изменения состояния окна (зачем?) grab release .dialog Можно сделать "глобальный" перехват событий, то есть нельзя работать даже с другими программами: grab -global .dialog Стандартные диалоги tk_messageBox -title -message -icon {error info warning question} -type: abortretryignore, ok, okcancel, retrycancel, yesno, yesnocancel tk_getOpenFile tk_getSaveFile ИНФОРМАЦИЯ О СОСТОЯНИИ TK winfo Информация об окнах. Размеры экрана: winfo screenwidth $w winfo screenheight $w Существует ли: winfo exists .w Список дочерних окон: winfo children .w Название класса: winfo class .w (Button, Entry и т. д.) Предопределенные переменные: tk_version tk_strictMotif read/write Когда включено, некоторые дополнительные черты поведения Tk исчезают, например подсветка кнопки, когда машь заходит на ее зону.