Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force TkInter Scale slider to snap to mouse

Tags:

python

tkinter

When a GUI has a TkInter Scale and they click somewhere on the scale, the default behavior seems to be to slide the slider along the Scale in the direction towards the mouse (and then unexpectedly past their mouse).

What I'd want instead is to have the slider always jump to and stay attached to the user's mouse point while they're clicking anywhere on the slider. If they click to a particular point on the Scale, the slider should jump directly to that point.

I have some code below which attempts to do this but doesn't seem to work and I cannot find the reason for it.

import tkinter as tk
from tkinter import ttk

def show_values():
    print('w1 set to',w1.get())

def snapToVal1(val):
    scaleVal = float(w1.get())
    if int(scaleVal) != scaleVal:
        w1.set(round(float(val)))

def scaleFunc1(event):
    g = w1.grid_info()
    w1.set(round(8 * (event.y - g['pady'])/(w1.winfo_height() - 2*g['pady'] - 2*g['ipady']))-1)
    print('w1 set to',w1.get())

#---
root = tk.Tk()

f1 = ttk.Frame(root, relief = tk.GROOVE)

ttk.Label(f1, text='Stellar\nType').grid(row=0,column=0, columnspan=2,padx=2,pady=2)

for i,text in enumerate(['O','B','A','F','G','K','M','L']):
    ttk.Label(f1, text = text).grid(row=i+1,column=0,pady=5,padx=(2,0))

w1 = ttk.Scale(f1, to=7, command=snapToVal1, orient=tk.VERTICAL)
w1.grid(row = 1, column = 1, rowspan = 8, pady=5, padx=2, sticky='nsew')
w1.bind('<Button-1>',scaleFunc1)

f1.grid(row = 0, column = 0,padx=(2,1),pady=2,sticky='nsew')

ttk.Button(root, text='Show', command=show_values).grid(row=1,column=0)

root.mainloop()

The pertinent function here is scaleFunc1. The idea is to have this called whenever the user presses their mouse button on the scale. It then tries to calculate, from the event pixel location and the Scale size, the fractional position of the click on the scale, convert this to a scale value, and set it to that value where the user clicked. However, I'm finding that the slider doesn't always jump to the same place, even if it reports it was set to the value I'd expect. What's going on?

I suspect it has something to do with the slide still trying to move for the fraction of a second the user keeps the mouse button pressed down.

like image 399
zephyr Avatar asked Mar 15 '17 18:03

zephyr


People also ask

How do you use scale In Tkinter?

Scale in Tkinter: Tkinter Tutorials | Python Tricks The Scale widget in Tkinter is used to select from a range of numbers through moving a slider. You can set the minimum and maximum values The Scale widget in Tkinter is used to select from a range of numbers through moving a slider.

How to create a slider in Tkinter?

A slider allows you to enter a value by moving an indicator. A slider can be vertical or horizontal: To create a slider, you’ll use the ttk.Scale () constructor as follows: In this syntax, the container specifies the parent component of the slider. The from_ and to options specify the minimum and maximum values of the slider.

How do you create a slider in Python?

A slider allows you to enter a value by moving an indicator. A slider can be vertical or horizontal: To create a slider, you’ll use the ttk.Scale () constructor as follows: ttk.Scale (container,from_,to) Code language: Python (python) In this syntax, the container specifies the parent component of the slider.

What is the default CURSOR type of the scale?

The default is a pointed arrow cursor. 6 digits It is used to specify the digits that are to be displayed on the range on the scale. 7 font Determines the type of font that is used for the scale. 8 fg Determines the foreground color of font that is used for the scale. 9 from_ Specifies starting end of the scale range. 10 highlightbackground


1 Answers

That's actually the default right-click behavior. If you want to make the left click do that too, then the easiest thing is to simply detect leftclick and tell tkinter it was a right click instead:

import tkinter as tk
from tkinter import ttk

class Scale(ttk.Scale):
    """a type of Scale where the left click is hijacked to work like a right click"""
    def __init__(self, master=None, **kwargs):
        ttk.Scale.__init__(self, master, **kwargs)
        self.bind('<Button-1>', self.set_value)

    def set_value(self, event):
        self.event_generate('<Button-3>', x=event.x, y=event.y)
        return 'break'

def show_values():
    print('w1 set to',w1.get())

root = tk.Tk()

f1 = ttk.Frame(root, relief = tk.GROOVE)

ttk.Label(f1, text='Stellar\nType').grid(row=0,column=0, columnspan=2,padx=2,pady=2)

for i,text in enumerate(['O','B','A','F','G','K','M','L']):
    ttk.Label(f1, text = text).grid(row=i+1,column=0,pady=5,padx=(2,0))

w1 = Scale(f1, to=7, orient=tk.VERTICAL)
w1.grid(row = 1, column = 1, rowspan = 8, pady=5, padx=2, sticky='nsew')

f1.grid(row = 0, column = 0,padx=(2,1),pady=2,sticky='nsew')

ttk.Button(root, text='Show', command=show_values).grid(row=1,column=0)

root.mainloop()
like image 57
Novel Avatar answered Sep 26 '22 00:09

Novel