Прежде чем мы перейдем непосредственно к Tk, уделим немного внимания "немодным
новостям" из "тикль-мира". За время, отделяющее эту часть статьи
от ее предшественницы, произошло несколько существенных изменений. Так, версия
системы Tcl/Tk на момент написания статьи достигла 8.4.7, и, если вы пользуетесь
более старой системой, желательно обновить ее (или с основного ресурса
www.tcl.tk
-- для пользователей Unix-совместимых ОС, или с сайта компании
ActiveState).
Также обновилась версия замечательной интерактивной среды отладки Tcl/Tk-программ
RamDebugger, однозначно заслуживающей
установки на компьютер "тиклолюба".
Ну а теперь все готово к тому, чтобы запустить руки в еще один ящик с "тикль-инструментами"...
|
Две строки кода -- завершенное
GUI-приложение. Характерная особенность Tcl/Tk -- освобождение программиста
от массы деталей, неизбежных при программировании GUI на компилируемых языках
высокого уровня
|
|
Количество строк в "приложении"
не изменилось, но теперь можно использовать штатный для данной платформы
селектор цвета
|
|
Одна-единственная "кнопка"
Tk способна "рассказать о себе" практически все. Рефлексивность
Tk -- одно из серьезных достоинств этой библиотеки виджетов
|
|
|
Никаких команд перерисовки
окон, ничего лишнего. Все те же две строки кода... Достаточно только изменить
значение ресурса Tk -- и цвет кнопки меняется
|
Итак, Tk, он же -- Tool Kit, по-русски -- "набор инструментов". Лаконично,
но непонятно. По сути, Tk представляет собой комплект из мощной библиотеки виджетов
(сейчас мы уточним этот термин), имеющей самостоятельную ценность и допускающей
применение при разработке программ на компилируемых языках (например, C, C++,
Ada), и команд-инструментов Tcl, позволяющих создавать на этом языке интерактивные
программы с графическим пользовательским интерфейсом. Термин "виджет"
ничего таинственного не обозначает -- это окно, обладающее собственным характерным
видом на экране и поведением. Хорошо знакомые по GUI разных операционных систем
и прикладных программ элементы интерфейса -- кнопки, меню, диалоги, полосы прокрутки
и т. п. -- все это виджеты, т. е. самостоятельные окна. Естественно, для создания
завершенного приложения только виджетов недостаточно -- им необходимо придать
некоторый порядок. За упорядочение виджетов в Tk отвечают два фундаментальных
для практически всех GUI-подсистем механизма -- иерархии виджетов и геометрического
менеджера. Первый механизм обеспечивает формирование композитных виджетов из виджетов-примитивов
(это исключительно важная функция, и для ее поддержки в Tk присутствует специальный
виджет -- контейнер-фрейм, предназначенный исключительно для удобства образования
композитных элементов пользовательского интерфейса), второй отвечает за их взаимное
расположение на экране. Последнее важное на этом уровне ознакомления сведение
о Tk касается, естественно, архитектуры данной подсистемы -- она относится к классу
"управляемых событиями". Это означает, что в исполнении Tcl-приложения
с Tk GUI инициатива принадлежит пользователю -- именно он "генерирует"
события (изменяет координаты мыши, нажимает на кнопки и т. д.), на которые реагирует
программа. Tcl-инструменты Tk устроены таким образом, чтобы решать типовые задачи
можно было буквально за считаные минуты -- так, для большинства событий в них
предусмотрены обработчики по умолчанию, а в случае надобности программист может
одной командой "связать" (
bind
) виджет, событие и "реагирующий" на него код. Более того, причинно-следственный механизм "связывания" (причина -- событие, инициированное пользователем, следствие -- соответствующие действия программы) допускает формирование собственных иерархий. Это так называемые "классы связываний" (в терминах Tk --
bindtags
), отвечающие за поведение целой иерархии виджетов. И наконец, последнее необходимое высокоуровневое архитектурное понятие -- "фокус". В Tk в любой момент времени "в фокусе" системы находится один виджет -- это означает, что сообщения о событиях (например, о нажатиях клавиш) направляются системой этому виджету, т. е. инициируют его реакции на события. Tk располагает двумя основными моделями "фокусировки" виджетов -- инициируемой пользователем с помощью указателя мыши и при-нудительной, инициируемой программистом (что означает: программист может задавать находящийся в "фокусе" виджет, изменять "фокусировку" и даже перехватывать "фокусную информацию").
Теперь, без промежуточных отступлений, перейдем к конкретике связки Tcl--Tk. Вопросы использования библиотеки виджетов Tk из компилируемых программ оставляются читателю для самостоятельного ознакомления (естественно, в случае необходимости, так как связка Tcl--Tk обеспечивает все, что нужно для написания как "программ-однодневок", так и сложных программных комплексов с исключительно развитым GUI). Начнем с фундаментального -- с Tcl-синтаксиса описания иерархий виджетов в Tk. Благо, правила эти хорошо вписываются в синтаксические модели описания иерархий во многих языках программирования: корневое окно вашей программы обозначается символом "точка", затем следует имя виджета, являющегося первым непосредственным "потомком" корневого окна, затем, опять через "точку", следует "вложенный" в него "подвиджет" и т. д. Например, если мы хотим написать типовую первую Tk-программу (конечно же, "Здравствуй, мир!") и в ней использовать только один виджет-кнопку (назовем ее hellow), то ее полное иерархическое имя будет "
.hellow
" (что означает -- виджет с именем hellow, являющийся потомком корневого окна). Собственно, время для первой программы наступило -- ее текст мы разберем по косточкам:
button .hellow -text Say
Hello -command puts stdout
"Здравствуй, мир!"
pack .hellow -padx 50 -pady 10
Первое слово
button -- это, естественно, команда-инструмент Tcl (маленькое уточнение относительно "первое слово" -- пользователи Windows вполне могут ограничиться таким синтаксисом, для работающих в Unix-подобных ОС в начале примера надо добавить "бэнг-строку" с указанием пути к интерпретатору wish). Эта команда (
button) более чем детально "разжевана" в сопроводительной документации -- так, в chm-файле, поставляемом в комплекте ActiveState Tcl, ее описание находится в подразделе Tk Manual -- Widgets. Команда принимает в качестве параметров полное иерархическое имя создаваемого ею виджета "кнопка" и строку дополнительных опций. Каждая опция описывается подстрокой, начинающейся с символа "тире", за которым без пробела следует имя опции. В приведенном выше примере полное иерархическое имя "
.hellow
" указывает, что мы фактически создаем главное окно нашей "программы" и помещаем в него виджет-кнопку с именем
".hellow"
. Опция
-text Say Hello
не является специфической для виджетов-кнопок (
button) -- это одна из многих опций, которыми "оснащено" большинство виджетов Tk (последнее замечание не случайно -- когда вы будете самостоятельно осваивать виджеты Tk, не забывайте, что в документации такие общие опции вынесены в отдельный раздел). Она специфицирует строку текста, отображаемого внутри виджета (к слову, во многих виджетах расположением отображаемого текста можно дополнительно управлять -- например, его выравниванием). В данном случае строка "
Say Hello
" будет написана в отображаемой кнопке. Вторая опция специфична для виджета-кнопки и позволяет удобно ассоциировать определяемые программистом действия с одним событием -- отпусканием кнопки мыши # 1 (в ПК -- это по умолчанию левая кнопка) после нажатия ею на виджет-кнопку. Здесь ассоциированное действие настолько примитивно, что для него не требуется написания процедуры или функции -- оно помещается в одну строчку и делает именно то, что ожидается от такой канонической программы, -- выводит в стандартный поток вывода фразу "Здравствуй, мир!". Итак, это была пока всего одна команда Tcl --
button (синтаксические принципы языка и механизм формирования команд описаны в предыдущих статьях данного цикла). Вторая строка -- новая команда, ее имя --
pack. Эта команда -- Tcl-интерфейс к одному из встроенных геометрических менеджеров Tk, который размещает виджеты "потомков" относительно границ их "предков". В данном случае виджет с именем hellow располагается в корневом окне программы, а специфика размещения указывается опциями (правила задания опций мы уже оговорили):
-padx 50
специфицирует, что измеряемый по горизонтали экрана отступ кнопки от левой и правой границ корневого окна программы должен быть 50 пикселов,
-pady 10
аналогично устанавливает отступы от верхней и нижней границы корневого окна в 10 пикселов. Вот, собственно, и все. Остальное, например реакции на стандартные GUI-события (касающиеся, в первую очередь, поведения корневого окна программы), мы даже и не вспоминаем -- Tk здесь полностью берет все на себя, а наша программа готова к исполнению. И, естественно, она выполняется именно так, как и ожидалось.
А теперь давайте немного модифицируем нашу первую программу, изменив в ней только реакцию на событие:
button .hellow -text
Say Hello -command
clipboard clear ;
clipboard append
"Здравствуй, мир!"
pack .hellow -padx 50 -pady 10
В данном примере вместо идеологически правильного в неинтерактивных скриптах приема -- вывода в стандартный поток -- мы применили не менее идеологически правильный для интерактивных программ прием вывода... в буфер копирования. В нем используется команда clipboard (полное описание в документации -- в разделе Tk Manual -- Inter-Client Communication), причем синтаксис ее настолько прост, что ни в каких дополнительных пояснениях не нуждается -- сначала буфер копирования очищается, затем к его содержимому добавляется строка "Здравствуй, мир!". Можно попробовать самостоятельно "ликвидировать" в этом примере очистку буфера копирования и, понажимав несколько раз на кнопку Say Hello, убедиться в том, что команда
clipboard
с опцией
append
именно добавляет что-то к содержимому буфера, а не полностью переписывает его. Этот пример не случаен -- он показывает один из путей создания простейших, но очень полезных Tcl/Tk-программ. А именно, GUI-утилиток буквально из нескольких десятков строк кода, позволяющих удобно интерактивно задавать... опции для хороших, но перегруженных излишествами программ командной строки (в конце концов, удерживать в голове три-четыре десятка опций командной строки нечасто используемой программы нерационально, а каждый раз "подглядывать" в руководство -- неудобно).
Если бы в перечне виджетов Tk были только кнопки, естественно, этот инструментальный набор не -заслуживал бы нашего внимания. Кроме кнопок, Tk располагает уже упомянутыми ранее фреймами (команда
frame
), мощным примитивом, создающим окно со структурированной графикой (команда
canvas
), очень функциональными так называемыми радиокнопками (
checkbutton
, кнопки с фиксацией состояния -- в отличие от обычных радиокнопки не только "помнят" свое состояние, но и характеризуются двусторонним ассоциированием со значениями указанных глобальных переменных Tcl -- как изменение пользователем состояния радиокнопки автоматически приводит к изменению значения переменной, так и изменение ее значения автоматически отображается изменением состояния кнопки), списками выбора, меню, полосами прокрутки, ключевым компонентом построения редакторов текста (команда
text), а также несколькими мощными специфическими примитивами GUI. Кроме базовых виджетов, в состав Tk входят также готовые общеупотребительные "мегавиджеты" -- например, стандартный диалог селектора цвета
tk_chooseColor
(попробуйте в предыдущем примере изменить реакцию кнопки
hellow
, например так:
-command tk_choose-Color -title "Выберите цвет"
). Кроме этого, развивавшаяся десятилетиями и продолжающая развиваться система обросла множеством мощных расширений -- библиотек "мегавиджетов" (это принятый в мире тикль термин, обозначающий композитные повторно используемые конструкции для создания GUI-приложений), так что зачастую, прежде чем пытаться написать какой-то высокоуровневый элемент GUI, стоит поискать подходящую, уже отлаженную его реализацию. Перечень заслуживающих внимания библиотек начинают уже ставшие де-факто стандартными разработки
BLT,
BWidgets,
Tix. Что же касается геометрических менеджеров, то уже обсужденная команда
pack -- далеко не единственная в системе. Кроме нее, можно использовать геометрический менеджер, обеспечивающий "абсолютное расположение на резиновом листе" (команда
place), -- размещенные ею виджеты-потомки могут автоматически изменять размеры при изменении размеров окна предка. Если требуемое расположение характеризуется регулярностью, можно воспользоваться сеточным геометрическим менеджером (его еще называют "табличным", команда
grid). И наконец, можно динамически изменять иерархию виджетов (в терминах GUI-систем часто оперируют понятием "стековый порядок", stacking order) командами
lower и
rise.
Теперь, когда вы вкратце знакомы с двумя основными принципами построения GUI -- образованием иерархий из виджетов и размещением виджетов (пусть это знакомство проводилось на очень простом примере -- фундаментальные принципы от этого не меняются, и более сложные конструкции будут отличаться разве что объемом практически типового кода), можно перейти к более сложным вещам. Начнем мы с... объектно-ориентированных свойств виджетов Tk. Несмотря на то что Tcl/Tk реализована на далеком от объектной ориентации языке C, Tk можно назвать образцовой объектно-ориентированной подсистемой. Каждый виджет в ней -- независимо от его типа, инкапсулирует массу информации, отве-чающей за его вид и поведение. И для доступа к этой информации ис-пользуется весьма специфическая конструкция вида "
полное_иерархическое_имя_виджета config необязательные_опции". Давайте немного модифицируем наш пример и приведем его к такому виду:
button .hellow -text
Параметры виджета button
-command clipboard clear ;
clipboard append [.hellow config]
pack .hellow -padx 50 -pady 10
В общем, модификации не так уж и страшны -- мы изменили надпись на кнопке (теперь она -- "Параметры виджета button") и реакцию на отпускание пользователем нажатой кнопки GUI
hellow. Результат мы заносим в предварительно очищенный буфер копирования, а вот этим самым результатом является перечень (точнее -- список) всех параметров виджета button. Это один из вариантов применения указанной выше конструкции "
...config ...", при котором мы можем наблюдать так называемое свойство рефлективности Tk (термин "рефлективность", применяемый к программным и, в общем, к вычислительным системам, означает способность системы хранить полную информацию о самой себе и использовать эту информацию для -изменения поведения). Теперь произведем еще одну модификацию, выбрав из полученного перечня, например, параметр
-fg
(или
-foreground
):
button .hellow -text
Параметры виджета button
-command clipboard clear ;
clipboard append
[.hellow config -fg]
pack .hellow -padx 50 -pady 10
Здесь изменения минимальны -- мы только использовали уточняющий параметр, о котором хотим получить исчерпывающую информацию. Запускаем эту программу, нажимаем на кнопку "Параметры виджета button" и вставляем из буфера копирования результат:
-foreground foreground Foreground SystemButtonText SystemButtonText
. В этом случае виджет
.hellow рассказал нам о себе следующее: у него была запрошена информация о параметре "цвет выводимых объектов"
(-foreground
); данному параметру соответствует ресурс системы с именем
foreground
, относящийся к классу Foreground, для которого значение по умолчанию равно значению переменной
SystemButtonText
и текущее значение также равно
SystemButtonText
(пользователи Unix-подобных систем в качестве значений могут получить в результате выполнения этой программы принятые в X Window описатели цвета в формате "#шестнадцатеричное_число"). Понятие ресурсов -- еще одно фундаментальное в Tk. Оно обозначает иерархическую информационную базу параметров виджетов, допускающую как модификацию одного параметра выбранного виджета, так и одновременную -- всех виджетов иерархии или множества параметров одного класса для виджетов разных иерархий. Мы же ограничимся последней модификацией нашего примера для демонстрации возможности интерактивной модификации одного из ресурсов Tk -- например цвета фона кнопки
hellow:
button .hellow -text
Параметры виджета button
-command .hellow config
-bg [tk_chooseColor
-title "Цвет фона"]
pack .hellow -padx 50
-pady 10
Здесь мы использовали только уже известные по этому краткому обзору конструкции, с единственной оговоркой -- диалог tk_chooseColor возвращает в вызывающую Tcl-программу выбранный цвет. Теперь, нажимая на кнопку GUI "Параметры виджета button", мы сначала активируем диалог выбора цвета (почему сначала -- в предыдущих статьях цикла), затем результат выбора пользователем с помощью конструкции типа "
.hellow config -bg цвет
" присваивается значению ресурса background виджета .hellow и... кнопка автоматически меняет цвет своего фона -- не нужны ее "перерисовки вручную" и прочие присущие GUI-программам "извращения".
Ready, set, buy! Посібник для початківців - як придбати Copilot для Microsoft 365