Как разработать диалоговую шкалу в tcl / tk, которая получает значение цикла и обновляет масштабный виджет, перемещая его - PullRequest
1 голос
/ 26 октября 2019

Я пытаюсь создать диалоговое окно с индикатором выполнения, например, GNU / Linux Xdialog --gauge

По-видимому, вы должны получить значение, которое обновляется за одну секунду, извремя от времени.

Это приращение выполняется с помощью цикла for, уже предварительно настроенного для последовательного подсчета.

Из моих тестов и того, насколько далеко я знаю tcl / tk может пойти так:

proc bar { pos } {
global txt
set txt $pos
}

set btn [button .btn -text "Play" -relief groove -command { bar $pos }]

scale .scl -length 200 -width 5 -orient horizontal -from 0 -to 100 -resolution 1 -variable value -sliderlength 5 -sliderrelief flat -activebackground blue -command { bar } -showvalue 0

label .lbl -textvariable txt -width 5

grid $btn -row 0 -column 0
grid .scl -row 0 -column 1
grid .lbl -row 0 -column 2

global value
for {set value 0} {$value < 10} {incr value} {  
after 1000; # delay
if {$value < 10} { puts "Number: $value" }
bind . "$btn invoke"
}

Это работает, так что в консоли ... он не показывает форму, окно с медленно перемещаемым виджетом масштаба. Так что мне нужна помощь самого опытного, как я могу получить это?

Я создал многокадровую анимацию, чтобы получить лучшее представление. Смотрите:

enter image description here

Ответы [ 2 ]

1 голос
/ 27 октября 2019

Команда

after 1000; # delay

просто блокирует и не позволяет Tcl / Tk выполнять какую-либо обработку. Поскольку ваша программа еще не вошла в цикл обработки событий, ничего не будет отображаться.

В некоторых случаях любой код, заканчивающийся заменой команды after, будет иметь задержки, которые позволят обновлять экран.

# don't put the bind inside the for loop
# is this even needed?
bind . "$btn invoke"

set ::waitvar 0
for {set value 0} {$value < 10} {incr value} {  
   # a simplistic solution for purposes of this example
   # vwait cannot be nested, and should be used very carefully or not at all.
   after 1000 set ::waitvar 1
   vwait ::waitvar
   set ::waitvar 0
}

Лучшим методом будет что-то вроде:

  proc updateScale { v } {
     global value
     set value $v
  }

  proc checkProgress { } {
     # query the progress of the task and see how far along it is
     set progress [queryProgress]
     updateScale $progress
     after 1000 [list checkProgress]
  }

  # schedule a call to checkProgress to start things off.
  after 1000 [list checkProgress]
  # and now the program enters the event loop
1 голос
/ 27 октября 2019

Проблема в том, что у вас есть синхронная петля задержки. Вам нужен асинхронный, чтобы можно было обрабатывать обновления дисплея.

coroutine countUp apply {{} {  # <<< launch coroutine for asynchronous state
    global value
    for {set value 0} {$value < 10} {incr value} {
        after 1000 [info coroutine]; yield; # <<< suspend coro for 1 second
        puts "Number: $value"
    }
}}

(Можно написать этот код без сопрограммы, но код менее понятен.)

И вырекомендуется использовать ttk::progressbar, когда вы хотите индикатор выполнения. Правильные визуальные подсказки пользователя, что это такое и т. Д.

...