Завуалированная тривиальность |
||||
Главная | Программные продукты | Freesource программные продукты | Статьи по Tcl/Tk | Статьи | Контакт | Карта сайта | |||
|
Завуалированная тривиальностьУскорение выполнения команды expr Команда expr выполняет двойную подстановку своих аргументов. Сначала препроцессором команд, затем препроцессором выражений. Двойная подстановка замедляет скорость выполнения команды expr. Но, в подавляющем большинстве случаев, двойная подстановка не требуется. Чтобы избежать двойной подстановки, необходимо выражение заключить в фигурные скобки { }. Например: set a 5 set b 1 # Чаще всего, пишем так: expr $a - $b # Заключим в фигурные скобки, повысыв скорость в несколько раз: expr { $a - $b } Но, бывают случаи, когда без двойной подстановки не обойтись. Например: set a 5 set b 1 set sign - expr $a $sign $b Выбор способа хранения структурированых данных Пусть вам необходимо каким-то способом организовать хранение, в памяти программы, данных следующей структуры: # id - уникальный идентификатор # data - некие данные по уникальному идентификатору # id | data 1 {Это данные для один} 2 {Это данные для два} ... N {Это данные для N} Эти данные можно хранить как список списков: lappend ldata [list 1 {Это данные для один}] lappend ldata [list 2 {Это данные для два}] ... lappend ldata [list N {Это данные для N}] или как массив: set ldata(1) {Это данные для один} set ldata(2) {Это данные для два} ... set ldata(N) {Это данные для N} В последующем, понадобится извлечение данных по уникальному идентификатору. Получение денных из списка lsearch -index 0 -integer -inline $ldata $искомый_id работает в несколько сот раз медленнее, чем извлечение данных из массива $ldata($искомый_id) Хотя, если предполагается последовательный доступ к данным foreach el $ldata { # код по обработке одного элемента списка } хранение в списке - более предпочтительно. Десятисекундный таймер proc Timer10Seconds { # некий код функционала таймера # . . . after 10000 Timer10Seconds } Вынос тела цикла в отдельную процедуру Если у вас есть длинный цикл, оформление тела цикла отдельной процедурой, будет работать быстрее. # Первоначальный код цикла for { set i 0 } { $i < 1000000 } { incr i } { expr { $i * $i } } # Модифицированный, работающий быстрее, код цикла proc Body { i } { expr { $i * $i } } for { set i 0 } { $i < 1000000 } { incr i } { Body $i } "Размораживание" интерфейса Tk Рассмотрим случай, когда необходимо выполнять какую-либо длительную операцию (чтение по сети, загрузка локального файла), с небоходимостью максимально возможно обрабатывать пользовательские итерфейсные события - управление мышкой, клавиатурой и вызуализацией данных, полученных как результат длительной операции. Допустим нам необходимо получить по сети некий графический файл, и вызуализировать его в каком-то Tk виджете. Лучший способ для исключения "замораживания" интерфейса - выполнить длительную операцию в отдельном потоке. Но мы работаем с ограниченными по памяти системными ресурсами, как пример - MapTour под WinCE, и работа в потоке исключена. В таком случае, как один из способов, можно использовать механизм виртуальных событий Tk. # Создаём виртуальное событие на несуразную комбинацию клавиш event add <<TilesRecived>> <Control-Shift-Meta-a> # привязываем новосозданное событие к окну canvas bind $cnv <<TilesRecived>> [list Tiles:Visual $cnv %d] # Запускаем в нужный момент процедуру получения тайла (графического файла) из сети after idle [list Tiles:Get $cnv] proc Tiles:Get { cnv } { # Код по получению изображения из сети # . . . # бинарные данные изображения хранятся в переменной bdata # Получив данные, генерируем виртуальное событие # которое запустит функцию создания и визуализации изображения after idle [list event generate $cnv <<TilesRecived>> -data $bdata] } proc Tiles:Visual { cnv bdata } { # Создаём изображение set iname [image create photo -height 256 -width 256] $iname put $bdata # Визуализируем изображение на canvas в координате x,y $cnv create image $x $y -image $iname } Wrapping Часто необходимо урезать/расширить функционал стандартных функций или полностью его переопределить. Добавим для виджета label команду определения координат верхнего левого угла: # создаем виджет label с надписью "Coords" # виджет порождает новую команду - .l pack [label .l -text Coords] -padx 10 -pady 10 # переименуем команду .l в .l_old rename .l .l_old # опишем новое поведение для вызовов команды .l proc .l { args } { set cmd [lindex $args 0] if { $cmd eq "coords" } { # код новой команды определения координат update idletasks return [list [winfo rootx .l] [winfo rooty .l]] } else { # выполняем все стандартные команды виджета label eval .l_old $args } } # визуализируем координаты в label .l configure -text [.l coords] Подобный приём можно использовать в довольно многих случаях. Например, для создания мегавиджетов - это виджет, состоящий из нескольких стандартных виджетов, но воспринимающийся системой как атомарный, целостный виджет. Полупрозрачность примитивов Canvas Как известно, примитивы canvas (линии, полигоны, ...) не обладают возможностью програчности. Но, данную проблему можно решить используя маску bitmap изображения. Так выглядит регион (подложка для кнопок) в обычном случае (без применения bitmap маски):
# код примитива Регион без применения bitmap маски $canvas create rectangle $x1 $y1 $x2 $y2 -outline cyan4 -fill grey90 А так выглядит регион (подложка для кнопок) с bitmap маской:
# код примитива Регион с bitmap маской $canvas create rectangle $x1 $y1 $x2 $y2 -outline cyan4 -fill grey90 -stipple transparent.xbm Предварительно, необходимо создать bitmap-файл transparent.xbm следующей структуры: # bitmap-файл transparent.xbm #define transparent_width 2 #define transparent_height 2 static unsigned char transparent_bits[] = { 0x01, 0x02 }; В результате получили визуальную полупрозрачность подложки для кнопок. |
|||||||||||
Copyright © Эдуард Зозуля | ||||||||||||