После выхода первой статьи про svg-виджеты для tcl/tk прошло более года. За это время вышел не только tcl/tk версии 9.0, но и сам пэт-проект возмужал и продолжает взрослеть. Напомним, что проект svgwidgets, примеры и интерпретаторы tcl/tk с необходимыми пакетами для работы с svg-виджетами можно найти на github-е.
В проекте svgwidgets на github-е можно найти версию интерпретатора tclexecomp как для linux64 (папка tclexexcomp902), собранного из исходников tcl/tk-9.0.2, так и версию интерпретатора на базе tcl/tk-8.6 для платформ Linux64 и Win64 (папка tclexecomp200).
К ранее созданному на github-е подкаталогу examples/CryptoArmPKCS_Test, в котором выложен исходный код криптографической утилиты для работы с электронной подписью cryptoarmpkcs, который предназначен для запуска на платформе Linux64 в среде tcl/tk-9, добавлены аналогичные папки для запуска утилиты cryptoarmpkcs в среде tcl/tk-8.6 на платформах Linux64 (папка examples/CryptoArmPKCS_Test_Tk86) и Win64 (папка examples/CryptoArmPKCS_Test_Tk86_Win64). Для запуска этой утилиты ничего дополнительного устанавливать на свой компьютер не требуется. Достаточно выбрать соответствующий интерпретатор из папки tclexecomp200 или tclexexcomp902 и выполнить файл mainguipkcs_svg.tcl из соответствующей папки ~/examples/CryptoArmPKCS_Test, например:
C:>C:\Temp\tclexecomp64_v200_svg_Win64.exe c:\Temp\CryptoArmPKCS7_Test_Tk86_Win64\mainguipkcs_svg.tcl

При подготовке этой статьи использовался графический интерпретатор tclexexcomp902, который поддерживает tcl/tk-9.
Напомним, что svg-виджеты могут создаваться каждый на отдельном холсте, а затем отображаться с помощью одного из диспетчеров компоновки (pack, grid, place), или могут создаваться все или группа виджет на одном и том же холсте. При размещении нескольких svg-виджетов на одном холсте диспетчеры компоновки не используются, их размещение на холсте задается опциями –x и –y.
P.S. Пожалуйста, не судите мои цветовые предпочтения и дизайнерские способности слишком строго. Здесь демонстрируются возможности инструмента.
Итак, для начала загружаем пакет svgwidgets и создаём окно .win1 размером 7 см на 12 см:
package require svgwidgets
toplevel .win -bg yellow
wm geometry .win [winfo pixels .win 7c]x[winfo pixels .win 12c]
Следует иметь в виду, что точность соответствия размеров окна задаваемым значениям ширины и высоты зависит от значения коэффициента масштабирования (tk scaling), который на моем компьютере в момент написания статьи был равен 1.8.
Теперь можно создать svg-фрейм с идентификатором frame1 на холсте .win.fr1 и разместить его в созданном окне .win:
cbutton create frame1 .win.fr1 -type frame -strokewidth 2m -stroke cyan -rx 0 -fillnormal white
#Можно svg-фрейм создать и так:
#cframe create frame1 .win.fr1 -type frame -strokewidth 2m -stroke cyan -rx 0 -fillnormal white
#Размещение svg-фрейма в окне
pack [frame1 canvas] -in {.win} -fill both -expand 1
#Или
#pack .win.fr1 -fill both -expand 1
Можно также вместо обычного svg-фрейма создать и svg-фрейм с заголовком, предварительно уничтожив созданный фрейм frame1:
frame1 destroy
cframe create frame1 .win.fr1 -type clframe -text {Фрейм с заголовком} -strokewidth 2m -stroke cyan -rx 0 -fillnormal white -fillbox cyan -fontsize 5m
#Прямоугольное выделение заголовка фрейма (цвет: -fillbox)
frame1 boxtext
Если задать опцию -rx равную 0 (нулю), то фрейм будет прямоугольной формы. Если окантовка не требуется, то достаточно задать опции «-stroke {} -strokewidth 0». Заливка фрейма определяется опцией -fillnormal.
Теперь создадим на холсте .win.fr1, на котором уже располагается svg-фрейм frame1, несколько svg-виджетов класса cbutton (кнопки), размещаемые вертикально:
#Расстояние между виджетами по вертикали 15 миллиметров
set y0 [winfo pixel .win.fr1 15m]
#Координата по вертикали для первой кнрпки
set y1 $y0
#Создаем пять кнопок: "rect round ellipse square circle "
#При нажатии на кнопку печатается её идентификатор
foreach tbut "rect round ellipse square circle " {
cbutton create b$tbut .win.fr1 -type $tbut -x 2c -y $y1 -text "ID: b$tbut" -command "puts \"Нажата кнопка b$tbut]\""
incr y1 $y0
}
Результат можно видеть ниже на левом скриншоте:

Сразу отметим, что фрейм масштабируется при изменении размеров окна, в котором он размещен (команда wm geometry <окно> <шипина>x<высота>[+x+y] или растягивание окна за одну из его вершин или одну из его сторон) (средний скриншот):
wm geometry .win [winfo pixels .win 8c]x[winfo pixels .win 13c]
Здесь мы применили команду wm geometry для увеличения окна .win до размеров 8сь на 13 см.
Напомним, что основные претензии, которые порой предъявляются классическим tk-виджетам, связаны с тем, что они имеют прямоугольную форму, что используется только одноцветная заливка виджетов и отсутствует возможность задавать прозрачность у виджетов. Все эти недостатки отсутствуют у svg-виджетов.
Для примера, установим градиентную заливку на svg-фрейме frame1 (см. средний скриншот выше):

#Вызов генератора градиента
set grad1 [ ::gengrad::generateGradient .win.fr1]
#Утилита генерации градиента завершена.
#gradient create linear -method pad -units bbox -stops { { 0.00 #57f1b3 1.00} { 1.00 #c63e31 1.00}} -lineartransition {0.00 0.00 0.00 1.00}
#Создание градиентой заливки
set ngrad1 [eval [frame1 canvas] $grad1]
#Установка градиента на svg-фрейм frame1:
frame1 config -fillnormal $ngrad1
#Вызов генератора градиента
set grad1 [ ::gengrad::generateGradient .win.fr1]
#Утилита генерации градиента завершена.
#gradient create linear -method pad -units bbox -stops { { 0.00 #57f1b3 1.00} { 1.00 #c63e31 1.00}} -lineartransition {0.00 0.00 0.00 1.00}
#Создание градиентой заливки
set ngrad1 [eval [frame1 canvas] $grad1]
#Установка градиента на svg-фрейм frame1:
frame1 config -fillnormal $ngrad1
Для полноты картины покажем как работает прозрачность. Прозрачность регулируется двумя опциями. Опция -fillopacity устанавливает степень прозрачности собственно заливки, а опция -strokeopacity – прозрачность окантовки. В нашем примере (см. правый скринщот выше) установим для svg-фрейма frame1 прозрачность равную 0.7, полную прозрачность для кнопки bround и частичную прозрачность для кнопки bellipse:
frame1 config -fillopacity 0.7
bround config -fillopacity 0
bellipse config -fillopacity 0.5
Более полный и интересный пример можно найти на github-е в папке examples, файл скрипт_button_Холст.tcl:

Примечательно в этом примере то, что при щелчке правой кнопкой мыши на главном окне примера будет напечатан идентификатор svg-виджета, на котором находится курсор. В примере это реализуется через вызов процедуры selectwsvg. Это может помочь в экспериментах с заливкой, прозрачностью и т.п. в данном примере.
А теперь посмотрим, как изменится наш пример, если каждый виджет будет располагаться на отдельном, персональном холсте.
Для начала уничтожим все созданные кнопки, фрейм frame1 и окно .win:
foreach tbut "rect round ellipse square circle" {
b$tbut destroy
}
frame1 destroy
destroy .win
В этом случае для размещения svg-виджетов будут использоваться диспетчеры компоновки (pack, grid, place), а опции -x и -y будут игнорироваться.
Что касается создание окна и главного svg-фрейма frame1, то все аналогично предыдущему примеру:
package require svgwidgets
toplevel .win -bg yellow
wm geometry .win [winfo pixels .win 7c]x[winfo pixels .win 12c]
cbutton create frame1 .win.fr1 -type frame -strokewidth 2m -stroke cyan -rx 0 -fillnormal white
pack [frame1 canvas] -in {.win} -fill both -expand 1
А вот что касается самих кнопок и их размещения (будем использовать диспетчер компоновки pack), то код будет несколько иной:
#Создаем пять кнопок: "rect round ellipse square circle "
#При нажатии на кнопку печатается её идентификатор
foreach tbut "rect round ellipse square circle " {
cbutton create b$tbut .win.$tbut -type $tbut -text "ID: b$tbut" -command "puts \"Нажата кнопка b$tbut]\""
pack .win.$tbut -in .win.fr1 -fill both -expand 1 -padx 1c -pady {5m 0}
if {$tbut == {circle}} {
pack configure .win.circle -pady {5m 1c}
} elseif {$tbut == {rect}} {
pack configure .win.rect -pady {1c 0}
}
}
И здесь может у вас произойти конфуз. Если при создании кнопки цвет, задаваемый опцией -bg (-bacground), будет отличаться от значения опции -fillnormal фрейма, в котором размещается кнопка, то этот цвет будет как бельмо в глазу. А если у фрейма градиентная заливка, то тем более. Для решения этой проблемы у svg-виджетов имеется метод fon, который можно применить к каждой кнопке. Но сегодня есть более изящный способ, который сам решает вопрос согласования цветов. Он состоит в том, чтобы, после размещения на фрейме всех виджетов, просто переустановить заливку (-fillnormal) или прозрачность (-fillopacity) фрейма:
<id-фрейма> config -fillnormal [<id-фрейма> config -fillnormal]
#или
<id-фрейма> config -fillopacity [<id-фрейма> config -fillopacity]
В нашем примере (левый скриншот) это выглядит так:
frame1 config -fillnormal [frame1 config -fillnormal]

Дальше опять без изменений как в предыдущем примере меняем размеры и делаем градиентную заливку (средний скриншот):
wm geometry .win [winfo pixels .win 8c]x[winfo pixels .win 13c]
set ngrad2 [[frame1 canvas] gradient create linear -method pad -units bbox -stops { { 0.00 #57f1b3 1.00} { 1.00 #c63e31 1.00}} -lineartransition {0.00 0.00 0.00 1.00}]
frame1 config -fillnormal $ngrad2
Далее устанавливаем прозрачность (правый скриншот):
bround config -fillopacity 0
bellipse config -fillopacity 0.5
frame1 config -fillopacity 0.7
Обратите внимание, что прозрачность у фрейма frame1 устанавливается в последнюю очередь в отличии от первого примера (все виджеты размещаются на одном холсте), где очерёдность применения этой опции не имеет значения.
И вы, наверное, заметили моргание на своём экране. Это и есть главное отличие размещения svg-виджетов на одном холсте или размещение каждого виджета на персональном холсте. И пока не удаётся разрешить эту проблему.
В папке examles на github-е можно посмотреть примеры скрипт_button_PACK_gradient.tcl и скрипт_button_PACK_gradient_opacity.tcl:

В этих примерах, также как и в примере скрипт_button_Холст.tcl, при щелчке правой кнопкой мыши на главном окне примера будет напечатан идентификатор svg-виджета, на котором находится курсор. В этих примерах это обеспечивает вызов процедуры selwsvg. Это может помочь в экспериментах с заливкой, прозрачностью и т.п. в этих примерах.
Но если, всё же, используется вариант создания каждого svg-виджета на отдельном холсте при разработки GUI, но все вопросы с заливкой и прозрачностью решаются на этапе проектирования, то этот недостаток проявляется очень редко.
Именно это и демонстрирует GUI утилиты CryptoArmPKCS, с рассказа о которой и началось наше повествование:

stan_volodarsky
Найдите на проект нормального дизайнера. Встречают по одёжке, пока встречают не очень.