Продолжим знакомство с svg-виджетами для tcl/tk. Напомним, что рассматриваемые примеры, сам пакет svgwidgets и интерпретаторы tcl/tk с необходимыми пакетами можно найти на github-е. После выхода первой статьи все они претерпели изменения. Начнем мы статью с рассмотрения примера скрипт_button_PACK.tcl:
$/usr/local/bin64/tclexecomp140_svg_Linux64 скрипт_button_PACK.tcl
В этом примере добавлена кнопка для запуска интерпретатора tclexecomp. При нажатии на эту кнопку появляется окно консоли, а кнопка перепрофилируется в кнопку скрытия консоли:
Если щелкнуть по любой из кнопок (кроме кнопки управления консоли), то в консоли будет напечатан идентификатор объекта кнопки. Итак, щелкаем по кнопке Эллипс и в консоли получаем следующий результат:
%
Эллипс=::oo::Obj61 Левый фрейм=::oo::Obj58
%
Посмотрим заливку объекта «левый фрейм»:
%::oo::Obj58 config -fillnormal
snow
%
Поменяем заливку фрейма с цвета снега (snow) на голубую (cyan):
%::oo::Obj58 config –fillnormal cyan
Мы видим, что виджеты не прямоугольной формы имеют прямоугольное обрамление с заливкой отличной от цвета виджета, в котором они размещены. Это обрамление имеет цвет холста, на котором размещен виджет:
% [::oo::Obj61 canvas] configure -background
-background background Background #d9d9d9 snow
%
Это уже знакомый нам цвет снега snow. Чтобы все привести в порядок необходимо наследование заливки -background для стандартных виджетов или –fillnormal для svg-виджетов. В нашем примере это можно сделать следующим образом:
% set colframe [::oo::Obj58 config -fillnormal]
cyan
% foreach wincan [pack slaves [::oo::Obj58 canvas]] {$wincan configure -background $colframe }
%
А что будет, если заливку cyan заменить на градиентную заливку?
Для начала создадим градиентную заливку для нашего фрейма:
% set gradCloud [[::oo::Obj58 canvas] gradient create linear -method pad -units bbox -stops { { 0.05 "#87ceeb" 1.00} { 0.17 "#ffffff" 1.00} { 0.29 skyblue 1.00} { 0.87 "#ffffff" 1.00} { 1.00 skyblue 1.00}} -lineartransition {1.00 0.00 0.75 1.00} ]
gradient5
%
После создания градиента зальем им наш холст:
% ::oo::Obj58 config -fillnormal gradient5
%
Мы снова столкнулись с той же проблемой, что и при смене просто цвета заливки, но разрешить эту проблему тем же способом не удастся. Кстати, такая же проблема возникает при использовании для размещения виджеты компоновщика place. И тут нам на помощь приходит пакет treectrl, в котором есть функция loupe.
Эта функция позволяет делать снимок любого участка экрана, а при желании, и масштабировать его. Отсюда и название функции loupe:
loupe <имя image> <x> <y> <w> <h> [<zoom>],
где поле <имя image> содержит идентификатор изображения, создаваемого командой
image create photo –width <ширина> -height <высота>
Координаты x и y задают центр снимаемой области (подчеркиваю, ЦЕНТР), w – это ширина области, а h – высота снимаемой области.
Таким образом, функция loupe снимает (делает скриншот) участок со следующими координатами:
X0 = x – w/2, y0 = y – h/2
X1 = x + w/2, y1 = y + h/2
Для решения вышеуказанной проблемы был реализован в каждом классе svg-виджетов метод fon. Задачей этого метода является сделать снимок участка экрана, на котором будет размещен svg-виджет и разместить этот снимок на нижнем слое холста виджета.
Если внимательно посмотреть на команду foreach, то можно заметить, что для виджета ::Прямоугольник метод fon не применялся. Для прямоугольных виджетов его можно не применять, картинка будет закрыта самим виджетом. Но тут есть нюанс. Этот нюанс связан с прозрачностью виджета. SVG-виджеты могут быть прозрачными. Прозрачность svg-виджетов задается через опцию –fillopacity, которая может принимать значение от 0 (полностью прозрачный виджет) до 1 (непрозрачный виджет). Прозрачность позволяет видеть либо цвет холста виджета (параметр -background), либо просматривать фон, на котором лежит виджет и который создается при вызове метода fon. Посмотрим на прозрачность на примере кнопки «Эллипс». Для начала установим его значение равным 1 (По умолчанию это значение не определено и виджет непрозрачен), а затем установим значение 0.5, т.е. сделаем полупрозрачным:
Для полной прозрачности svg-виджеты опция –fillopacity устанавливается в 0. Кстати, окантовка виджетов тоже может быть прозрачной (опция -strokeopacity).
Если вы попробуете изменить размеры окна (обратите внимание на стрелку в правом нижнем углу скриншота), то может быть нарушена градиентная заливка на холстах вложенных виджетов:
Чтобы исправить ситуацию, нужно повторно обратиться к методу fon:
%foreach obj "Прямоугольник ::oo::Obj95 ::oo::Obj96 ::oo::Obj97" {$obj fon}
%
А можно ли избежать этих недостатков? Да, можно. Все, что для этого нужно, так это размещать svg-виджеты на одном холсте с указанием координат каждого размещаемого виджета. Итак, создаем холст, на котором будем размещать необходимые нам svg-виджеты:
% set mainfr [cframe new .mainf -type frame -fillnormal yellow -rx 0 -strokewidth 0 -stroke ""]
::oo::Obj108
% ::oo::Obj108 pack -fill both -expand 1
%
По умолчанию для такого холста (класс cframe и тип frame) установлена обработка события <Configure>:
%bind .mainf <Configure>
::oo::Obj151 scaleGroup .mainf %w %h %x %y;::oo::Obj151 resize %w %h 0
%
На период разработки gui (отладки) можно отключить эту обработку, а по завершении ее можно будет восстановить:
%set bindorig [bind .mainf <Configure>]
% bind .mainf <Configure> {}
#разработка gui
#Восстановление обработки
% bind .mainf <Configure> $bindorig
%
Теперь на созданном холсте (.mainf или [::oo::Obj108 canvas]) можно размещать svg-виджеты, например:
%set went [cframe new .mainf -type centry -rx 2m -height 7m -x 25m -y 10m -width 10c]
При создании виджетов на уже существующем холсте необходимо явно указывать его коордитаты (опции –x и –y), а также высоту и длину виджета (опции –height и -width. Если опции –x и –y не указаны, то виджет размещается с координатами равными нулю. В этом случае для размещения виджета в нужном месте потребуется метод move (переместить):
<obj> move <dx> <dy>,
где dx и dy задают сдвиг по оси X и Y.
Если dx и dy равны 0, то метод возвращает дескриптор объекта:
%::oo::Obj065 move 0 0
canvasbObj65
%
Продвинутые юзеры могут его использовать для низкоуровнего конфигурирования svg-виджета.
Можно не только перемещать виджет, но и менять его размеры:
<obj> config [–width <новая ширина>] [-height <новая высота>]
При размещении svg-виджетов непосредственно на существующем холсте необходимость в методах fon, place, pack и grid отпадает, они в этом случае не используются.
Иногда бывает полезным скрыть (сделать невидимым) тот или иной виджет:
<obj> config –state hidden
Возврат виджета в нормальное состояние выполняется командой:
<obj> config –state normal
В примерах на github-е лежит скрипт скрипт_button_Холст.tcl. Если вы запустите его, то получите следующую картинку:
Как работает обработка события <Configure> можно увидеть, меняя размеры главного окна мышкой (стрелка в правом нижнем углу) или выполнением команды wm geometry:
Проект находится в начале пути, но уже сегодня с ним вполне можно создавать различные приложения с gui.
Кто-то может спросить, а что со средой разработки. На мой взгляд, графика tcl/tk настолько проста в использовании, что имея под рукой интерпретатор типа freewrap или его клон tclexecomp, можно достаточно быстро создать прототип графического интерфейса. Кстати, вместо freewrap и tclexecomp можно использовать и пакет tkcon.
Но все же, в голове сидит: "А почему бы не написать конструктор графического интерфейса?"
И вот параллельно с самим проектом потихоньку создается плагин (windowMegaWidgets.tcl), который можно будет использовать и в vTcl, и в TkProE, и даже в графическом редакторе tksvgpaint:
А там, глядишь, svg-виджеты перекочуют в python/Tkinter, а плагин станет доступен в графическом конструкторе Page для Python.
Но обо всем этом в следующих публикациях.
Добавим, что svg-виджеты, также как и tcl/tk, доступны на платформах Linux, Windows и Android.
Часть I. SVG-виджеты для tcl/tk
Часть II. SVG-виджеты для tcl/tk. Градиентная заливка и прозрачность.