[Tkinter-discuss] Scale widget fires command on entering mainloop?

Guilherme Polo ggpolo at gmail.com
Fri Nov 7 16:35:46 CET 2008


On Fri, Nov 7, 2008 at 1:32 PM, Guilherme Polo <ggpolo at gmail.com> wrote:
> On Fri, Nov 7, 2008 at 12:53 PM,  <david.giesen at kodak.com> wrote:
>> "Guilherme Polo" <ggpolo at gmail.com> wrote on 11/07/2008 09:23:48 AM:
>>>
>>> Comparing this Scale example with a command set and a Button with a
>>> command set is unfair. When you change Scale's value, the scale
>>> eventually has to be redraw.
>>>
>>> So, you create a Scale with the "command" option set, then you change
>>> its value by calling scale.set, then you run mainloop. When mainloop
>>> runs the scheduled events start firing, and there is one around there
>>> saying your scale changed its value so the slider has to be redrawn.
>>> But you also set a command, so, since the scale changed now it must be
>>> invoked, and the callback is called.
>>>
>>> Can you explain why is it a problem to invoke the callback if the
>>> scale has changed ? And why don't you want it to be called the first
>>> time.
>>>
>>> --
>>> -- Guilherme H. Polo Goncalves
>>
>> Thanks for the quick response and the explanation about there being a
>> scheduled events queue that waiting for the mainloop to start, Guilherme.
>> That's something I hadn't thought about and it explains why there is a
>> delayed command firing.  However, it doesn't change my thinking that the
>> command shouldn't be firing at all in these two cases.
>>
>> First off, I have no problem if the callback is invoked when the scale is
>> changed, that is why I'm using it.
>>
>> However, in the first case, I don't think of the scale being 'changed'.
>> I'm giving it the initial value via the Tkinter variable scalevar and I'm
>> not changing it, so I don't understand why the command gets called.  The
>> scale doesn't have to be redrawn, only drawn the first time.  Maybe my
>> original button argument wasn't the best, but I do see this as the same as
>> a Checkbutton.  I can pass in an initial value to the Checkbutton via a
>> Tkinter variable, and the Checkbutton command does not fire when the
>> mainloop starts (see the example below, which I've also fixed so it no
>> longer imports a custom module of my own - it should run for anyone now).
>>
>> And in the second case, there is no command callback registered at the
>> time that I change the scale value - the callback is added later via a
>> configure statement.  So again, I don't see why a callback is registered
>> for the change.  This behavior is again different from a checkbutton - if
>> I create a checkbutton with no callback, then change the value, then add a
>> callback function, the callback command is not called.  I've added both
>> the checkbutton examples to the code below for comparison.
>>
>> As for why I don't want the callback to be called when the widget is first
>> created, well I might have something in my callback routine that I only
>> want to occur in response to the user changing the initial scale value.
>> Regardless, it seems like quite non-standard and unexpected (to me)
>> behavior since other widgets don't do this.
>>
>> Dave
>>
>>
>> import Tkinter as Tk
>>
>> root = Tk.Tk()
>> def printme1(value):
>>        print 'Scale # 1 just fired with value:', value
>> scalevar = Tk.IntVar()
>> scalevar.set(7)
>> scale1 = Tk.Scale(root, command=printme1, variable=scalevar)
>> print 'Scale #1 initialized with value:', scale1.get()
>>
>
> Ok, it is understandable that you want the callback to not be invoked
> in this case, but unfortunately that is how scale works for now. It
> may not make a difference to the problem, but the behaviour of
> ttk.Scale is the one you are expecting.
>
>> def printme2(value):
>>        print 'Scale # 2 just fired with value:', value
>> scale2 = Tk.Scale(root)
>> print 'Scale #2 initialized with value: ', scale2.get()
>> scale2.set(4)
>> print 'Scale #2 just set to value: ', scale2.get()
>> scale2.configure(command=printme2)
>>
>
> Now this is basically the same as the example in the other email. It
> is differently internally in tkScale.c, but will result in the same
> actions. Calling scale2.configure includes setting the scale value to
> itself to ensure that the scale's value is within the new acceptable
> range for the scale (note that you didn't change its range, but
> unfortunately it does this anyway). When it goes to set the scale's
> value, the scale command is already set (you just gave it one), so it
> is scheduled for redrawn and the callback will eventually be called.
>
> To achieve what you want you will have to drop the "command" option
> usage and stick to tcl variables. In the first example in this email
> you already used an IntVar, now all you have to do is trace that
> variable for changes on it, specially when you write to it. This
> means:
>
> scalevar.trace_variable('w', callback)
>
> callback is a function that takes 3 arguments, the first is the
> variable name, the second is just used if you are using an tcl array
> (Tkinter.py doesn't wrap it), and the third argument will be the flags
> given to trace_variable ('w' here).
> To access the variable value in the callback you would do something
> like: root.globalgetvar(varname) where root could be Tkinter.Tk() for
> example, and varname would be the first parameter in the callback
> function.

root.tk.globalgetvar actually

>
>> def printme3():
>>        print 'Checkbutton # 1 just fired with value:', cbvar.get()
>> cbvar = Tk.IntVar()
>> cbvar.set(1)
>> cb1 = Tk.Checkbutton(root, variable=cbvar, command=printme3)
>> print 'Checkbutton #1 initialized with value: ', cbvar.get()
>>
>> def printme4():
>>        print 'Checkbutton # 2 just fired with value:', cbvar2.get()
>> cbvar2 = Tk.IntVar()
>> cbvar2.set(1)
>> cb2 = Tk.Checkbutton(root, variable=cbvar)
>> cb2.invoke()
>> print 'Just invoked cb2 with no callback'
>> cb2.configure(command=printme4)
>>

Just quickly commenting on these examples. Well, they are different
widgets after all. A checkbutton doesn't draw a slider, it is much
easier to control its values.

>> print 'Now packing scales'
>> scale1.pack()
>> scale2.pack()
>> cb1.pack()
>> print 'Done packing scales'
>>
>> root.mainloop()
>>
>
>
>
> --
> -- Guilherme H. Polo Goncalves
>



-- 
-- Guilherme H. Polo Goncalves


More information about the Tkinter-discuss mailing list