0

I cannot fix a strange behavior of spinbox. Specifically, I need to update GUI at changing the spinbox's value, by means of -command and update in it.

The code a bit simplified is like:

  package require Tk
  set sv 1
  ttk::spinbox .sp -from 1 -to 9 -textvariable ::sv \
   -command {
     after 50                 ;# some processing imitated
     puts [incr ::tmp]:$::sv  ;# changes shown in CLI - ok
     update                   ;# changes shown in GUI - ???
   }
  pack .sp

The problem is when the spinbox's arrow (more "Up" than "Down", but I've not found any regularity in this) is clicked and then pressed 10-20 seconds, the spinbox goes in the infinite cycle of updating, as puts shows.

Of course, the reason is update in the -command code, but I cannot do without it.

Tried in Windows (Tk 8.6.8) and Linux (Tk 8.6.10), ttk::spinbox and spinbox, all revealing the freak.

Is any way to overcome this? Thanks a lot for any help.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Alex P
  • 96
  • 1
  • 6
  • I cannot duplicate the issue. Move the processing outside of the loop as Donal specified in his answer. Move the update into the processing procedure. This type of callback should be kept very short. – Brad Lanam Nov 18 '20 at 14:59

2 Answers2

0

In general, don't update the spinbox variable from within the -command callback, and in particular don't run update from within the -command callback. You probably shouldn't do that at all. That command allows processing of events (it runs a subsidiary event loop until the event queue is drained) and is exactly the source of your problems. (I also would suggest not doing update idletasks; that will trigger the reconfigure and redraw that is at the heart of the issue.)

Instead, just stop running the command callback. That returns control to the Tk widget, which will in turn return to the main event loop. You are also advised to not do substantial processing in the callback, and instead to schedule such processing to occur later. Exactly how you do this can be complex, and will definitely be application-specific. One way to move processing later is to just punt it to a procedure that runs in an after event, like this:

package require Tk
set sv 1
proc updateVar {varName} {
    upvar "#0" $varName var
    after 50;  # Processing...
    incr var;  # Actually update the variable
}
ttk::spinbox .sp -from 1 -to 9 -textvariable ::sv \
    -command {after 0 updateVar ::sv}
pack .sp

Note that this does not call update. More substantial postponements of code might involve threads or subprocesses. As I said, getting this right can be complex. It's particularly so when changes to the GUI layout while a mouse button is down cause the selected value to change which in turn causes changes to the GUI layout which …

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • Thank you Donal, thank you Brad, I appreciate greately your advices. Knowing of `update considered harmful`, I had not prepared my question so well as it might be, e.g. to reproduce the issue (more detailed, with video and all). Mea culpa. Still, I'll try and do better with this question. – Alex P Nov 18 '20 at 16:15
0

I made this archive with video to demonstrate the strange behavior of spinbox when update is included in its -command option.

There are two tests in the archive:

test1.tcl presents a way how it should not be done. There are two issues:

  • the -command code isn't moved to a separate procedure
  • update is fired immediately from the -command code

The result is seen in test1-spx.mp4: when pressed a spinbox arrow 10-20 seconds, the spinbox goes into an infinite cycle of updating. This behavior is not regular, though well revealed when the focus is switched to another application.

test2.tcl presents a way how this freak can be overcome. The after idle is used to postpone the updating. You can use also after 0 for this.


In a "real test" test2_pave.tcl I use the following procedure for the -command:

proc fontszCheck {} {
  lappend ::afters [after 0 {
    foreach a $::afters {after cancel $a}
    set ::afters [list]
    ::t::toolBut 4 -3
  }]
}

Hopefully, this information would be useful at dealing with Tk spinbox.

Alex P
  • 96
  • 1
  • 6