4

I'm using the Scale widget in Tkinter to control the location of an object in another program. The user can both move the slider in the GUI or move the object directly from the external program. I want the slider value to always show the object's current position. The problem I'm running into is that both moving the slider and programmatically setting the slider with the set method both call the Scale widget's callback. I'd like to only have it called when it is physically moved.

What I've tried so far:

Following the suggestions from this answer, I tried using a flag and disabling the callback before calling set, but that didn't quite work in my case. There is a time delay in setting and reading the object's position and I think that is what is causing problems (I built a toy example where the slider was just hooked up to another slider, and the flag solution worked, but it didn't work for my real application). I'm also using the after function to periodically check whether the physical object is moved. I'm not sure if that is the best way to go or if that affects anything (it might be allowing the flag to be in the wrong state in parts of the code).

I think I'll have to try the suggestion of subclassing the widget, and then making my own version of the set method that sets a value, but does not call a callback. I'm not sure how to do that though, and from browsing through the source code of the widget it's not too clear where that all happens. Any help would be greatly appreciated, thanks!

2 Answers 2

6
+50

I was faced with the same issue and neither inhibiting the callback nor setting a global variable to check the callback status worked for me, for some obscure reason the callback kept being called after my code had finished running.

Despite this the solution that worked for me is simple : I used a variable in the widget and set the value using the set method of the variable rather than the one of the widget.

value = DoubleVar()
scale = Scale(master, variable=value, command=callback)
scale.pack()

scale.set(0) #<- this triggers the callback, no matter what I tried to stop it
value.set(0) #<- this works like the previous line but without any callback
Sign up to request clarification or add additional context in comments.

1 Comment

This saved me so much time I'm awarding a small bounty. Thanks.
-1

you could try something like this:

def program_move():
    inhibit_callback = True
    slider.value = #your value here

def callback(event, *args):
    If inhibit_callback:
        inhibit_callback = False
        return
    else:
        #whatever you were going to do

and i think this should allow the callback to work normally when its a user triggered callback, but when the program triggers it it should break immediately after the callback is triggered and resets its own flag.

1 Comment

Thanks for the suggestion! It doesn't quite work in my case, because I have to make the flag global in the callback and it can be changed by the other function at any time (program_move() is called by a timer, which goes off every 200ms or so) I think the flag is getting changed back before the slider value is changed some of the time

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.