强制TkInter Scale滑块捕捉鼠标

时间:2017-03-15 18:13:54

标签: python tkinter

当GUI有一个TkInter Scale并且它们点击比例尺上的某个位置时,默认行为似乎是沿着Scale向滑动方向滑动滑块(然后意外地超过鼠标)。

我想要的是让滑块始终跳转并保持与用户鼠标点的连接,同时他们点击滑块上的任意位置。如果他们单击“比例”上的特定点,滑块应直接跳到该点。

我在下面有一些代码试图这样做,但似乎没有用,我找不到它的原因。

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()

这里的相关功能是scaleFunc1。这个想法是每当用户在秤上按下鼠标按钮时调用它。然后,它尝试从事件像素位置和比例大小计算比例上点击的分数位置,将其转​​换为比例值,并将其设置为用户单击的值。但是,我发现滑块并不总是跳到同一个地方,即使它报告它被设置为我期望的值。发生了什么事?

我怀疑它与幻灯片有关,仍然试图移动一小段时间用户按住鼠标按钮。

1 个答案:

答案 0 :(得分:5)

这实际上是默认的右键单击行为。如果你想让左键单击也这样做,那么最简单的方法是简单地检测leftclick并告诉tkinter它是一个右键单击:

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()