Tk GUI не отвечает

#tcl #tk

#tcl #tk-toolkit

Вопрос:

Может ли кто-нибудь помочь мне в этой ситуации? Я пытаюсь создать графический интерфейс, который используется для демонстрации цветов всей матрицы RGB на холсте. К сожалению, графический интерфейс не отвечает и не меняет цвета, как ожидалось, пока цикл не будет завершен. Что-то не так? Я часто сталкиваюсь с этой проблемой, если настраиваю виджет в цикле.

 package require Tk
package require math
proc changeColor {rM gM bM} {
    for {set r 0} {$r<=$rM} {incr r} {
        for {set g 0} {$g<=$gM} {incr g} {
            for {set b 0} {$b<=$bM} {incr b} {
                set rHex [format X $r]
                set gHex [format X $g]
                set bHex [format X $b]
                set mark #
                set color [append mark $rHex $gHex $bHex]
                .cv config -bg $color
                .lb config -text "[format d $r] [format d $g] [format d $b]"
                after 500
            }
        }
    }
}

canvas .cv
ttk::label .lb
ttk::button .bt -text Run -command {changeColor 255 255 255}

grid .cv -row 0 -column 0 -sticky news
grid .lb -row 1 -column 0 -sticky we
grid .bt -row 2 -column 0
  

Code_Snapshot

GUI_Snapshot

Комментарии:

1. Попробуйте использовать update idletasks перед следующей строкой.

2. Привет, Марио, очень ценю вашу любезную помощь. Это работает.

Ответ №1:

Tk (и Tcl) вообще не обрабатывает события во время синхронного after 500 . Он просто останавливает процесс на эти 500 мс.

Вместо этого вам нужно обработать события за это время. Замените after 500 на:

 after 500 {set go_on yes}
vwait go_on
  

Имейте в виду, что go_on there является глобальным, и что это может вызвать проблемы с повторным вводом кода. Вы захотите отключить кнопку, которая запускает процедуру во время выполнения вашего кода.

Или вы можете использовать Tcl 8.6 и преобразовать все в сопрограмму. Тогда вы сможете выполнять асинхронный спящий режим без опасности заполнения стека:

 proc changeColor {rM gM bM} {
    for {set r 0} {$r<=$rM} {incr r} {
        for {set g 0} {$g<=$gM} {incr g} {
            for {set b 0} {$b<=$bM} {incr b} {
                set rHex [format X $r]
                set gHex [format X $g]
                set bHex [format X $b]
                set mark #
                set color [append mark $rHex $gHex $bHex]
                .cv config -bg $color
                .lb config -text "[format d $r] [format d $g] [format d $b]"
                ####### Notice these two lines... ########
                after 500 [info coroutine]
                yield
            }
        }
    }
}

##### Also this one needs to be altered #####
ttk::button .bt -text Run -command {coroutine dochange changeColor 255 255 255}

# Nothing else needs to be altered
  

Комментарии:

1. update idletasks казалось бы, работает, но у него будут проблемы, если вы сделаете что-то, что генерирует внешнее событие, например, перемещение или изменение размера окна…

2. Привет, Донал, большое спасибо за ваши подробные инструкции.