0

I have a GUI which contains a scale and a button widgets. When the button is clicked, it calls a function to delete the scale widget. I'd like this to happen only if the scale value has changed, that is, I want people to move the scale cursor before the button command could be activated. The default value on the scale is 0, and people are allowed to move the cursor and then come back on the 0. I've tried many things but couldn't figure out how to do it in a simple way.

Thank you in advance!

Here's a simplified version of my code :

from tkinter import *

def action(widget):
    widget.destroy()

window = Tk()

value = DoubleVar()
scale = Scale(window, variable=value, resolution=1)
button = Button(window, command = lambda: action(scale))

scale.pack()
button.pack()

window.mainloop()

Here's a new version using the .trace method, as suggested by @Sun Bear . It still doesn't work, the "action" function doesn't seem to get the updated state variable.

from tkinter import *

def scalestate(*arg):   
    scale_activate = True
    print("scale_activate is", scale_activate)

def action(widget):
    if scale_activate:
        widget.destroy()

window = Tk()

scale_activate = False
print("scale_activate is initially", scale_activate)

value = DoubleVar()
value.trace('w', scalestate)
scale = Scale(window, variable=value, orient=HORIZONTAL)

button = Button(window, command = lambda: action(scale))

scale.pack()
button.pack()
window.mainloop()

2 Answers 2

1

You can use .trace method to monitor the scale value and than toggle a state variable. Thereafter, method "action" can be used to check the state variable and the scale value before deciding to delete the scale widget or not.

The code below does according to your specification. You can explore ways to minimise the granularity of the conditions if you think it is too detailed.

Note, I changed your code to express it in a more object oriented manner. It makes implementing what you want easier. Also it is a very useful approach as you need to do more complicated things later.

import tkinter as tk

class SampleApp(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.scale_activate = False
        self.value = tk.DoubleVar()
        self.value.trace('w', self.scalestate) #add a trace to the scale variable
        self.scale = tk.Scale(parent, variable=self.value, resolution=1)
        self.button = tk.Button(parent,
                                command=lambda:self.action(self.scale))
        self.scale.pack()
        self.button.pack()

    def scalestate(self, *arg):
        # method to toggle scale has been activated
        if self.value.get():
            print('Tracing Scale value: ', self.value.get())
            self.scale_activate=True

    def action(self, widget):
        # method to delete scale widget according to your stated conditions
        if self.value.get():
            if self.scale_activate:
                print('self.value>0, self.scale_activate is True, delete scale')
                widget.destroy()
                self.scale_activate = False
                self.value.set(0.0)
            else:
                print('self.value>0, self.scale_activate is False')
                self.scale_activate = True
        else:
            if self.scale_activate:
                print('self.value==0, self.scale_activate is True, delete scale')
                widget.destroy()
                self.scale_activate = False
                self.value.set(0.0)
            else:
                print('self.value==0, self.scale_activate is False')
                self.scale_activate = False


if __name__ == "__main__":
    window = tk.Tk()
    app = SampleApp(window)
    window.mainloop()
Sign up to request clarification or add additional context in comments.

2 Comments

Your app works perfectly fine, this is exactly what I want, but mine doesn't use classes (but I know I should). @abccd 's solution works only partially because I cannot select the original value even after the cursor was moved; button doesn't activate. I've tried to use the .trace method with my app, but it doesn't work. The scale_activate variable changes from False to True when the cursor is moved, but it seems that the "action" function do not get the updated value of the state variable. I have edited my question to show a new version of my code, could you take a look? Thank you!
@PLdeChantal The issue is that scale_activate is a local variable. That is you have 3 scale_activate variables, 1 in main code and one in each function and they are not connected. One way is to make it global variable. Else, you will have to make sure that variable is passed from the main code to the function and back to the main code and to the functions, which I think to be quite inconvenient to do.
1

You can compare the values before destroying. And DoubleVar isn't useful for Scales. Since Scales has a get() function

from tkinter import *

def action(widget):
    If widget.get() != original:
        widget.destroy()

window = Tk()

scale = Scale(window, resolution=1)
original  = scale.get()
button = Button(window, command = lambda: action(scale))
scale.pack()
button.pack()
window.mainloop()

Comments

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.