TkInter、滑块:如何仅在迭代完成时触发事件?

问题描述 投票:0回答:3

我使用滑块来更新可视化,但每次移动滑块拇指时都会发送命令 updateValue,即使对于中间值也是如此。

相反,我只想在释放鼠标按钮并且交互完成时触发它。

self.slider = tk.Scale(self.leftFrame, from_=0, to=256, orient=tk.HORIZONTAL, command=updateValue)

如何在交互结束时仅触发该功能一次?

python tkinter
3个回答
57
投票

这是一个相当古老的问题,但如果有人偶然发现这个特定问题,只需使用bind()函数和“ButtonRelease-1”事件,如下所示:

import Tkinter as tk

class App:
    def __init__(self):
        self.root = tk.Tk()

        self.slider = tk.Scale(self.root, from_=0, to=256, 
                               orient="horizontal")
        self.slider.bind("<ButtonRelease-1>", self.updateValue)
        self.slider.pack()
        self.root.mainloop()

    def updateValue(self, event):
        print self.slider.get()

app=App()

希望这对任何人都有帮助!


9
投票

你不能。

您可以做的是让您的命令使用“after”在短时间内延迟任何实际工作。每次调用命令时,取消任何待处理的工作并重新安排工作。根据您的实际要求,半秒的延迟可能就足够了。

另一种选择是不使用内置命令功能,而是使用自定义绑定。要做到完全正确可能需要做很多工作,但如果您确实需要细粒度的控制,您可以做到。不要忘记,除了鼠标之外,还可以使用键盘与小部件交互。

这是一个简短的示例,展示了如何安排在半秒内完成的工作:

import Tkinter as tk

#create window & frames
class App:
    def __init__(self):
        self.root = tk.Tk()
        self._job = None
        self.slider = tk.Scale(self.root, from_=0, to=256, 
                               orient="horizontal", 
                               command=self.updateValue)
        self.slider.pack()
        self.root.mainloop()

    def updateValue(self, event):
        if self._job:
            self.root.after_cancel(self._job)
        self._job = self.root.after(500, self._do_something)

    def _do_something(self):
        self._job = None
        print "new value:", self.slider.get()

app=App()

0
投票

带有标签和值的去抖 tk 比例

tk_scale_debounced.py

import tkinter as tk
from tkinter import ttk

class tk_scale_debounced(ttk.Frame):

    """
    scale with after_change event

    aka: debounced scale

    example:

    def after_change(key, value):
        print(key, value)
    root = tk.Tk()
    s = tk_scale_debounced(root, "some label", after_change, "x", from_=-10, to=10)
    s.pack()
    """

    # current value
    value = None

    # debounce timer for keyboard input
    _change_key_timer = None

    def __init__(self, parent, label, after_change, key=None, **scale_kwargs):

        """
        example scale_kwargs:

        from_=-10, to=10, orient='horizontal'
        """

        super().__init__(parent)

        self._after_change = after_change
        self._label = label
        self._key = key or label

        self.value = tk.DoubleVar()

        self.columnconfigure(0, weight=2)
        self.columnconfigure(1, weight=1)
        self.columnconfigure(2, weight=100)

        # label
        self._scale_label = ttk.Label(self, text=self._label)
        self._scale_label.grid(column=0, row=0, sticky='w')

        # value
        self._value_label = ttk.Label(self, text=self._format_value())
        self._value_label.grid(column=1, row=0, sticky='w')

        #  scale
        self._scale = ttk.Scale(self, command=self._scale_change_live, variable=self.value, **scale_kwargs)
        self._scale.grid(column=2, row=0, columnspan=4, sticky='we')

        # mouse
        self._scale.bind("<ButtonRelease-1>", self._scale_change_done)
        # keyboard
        self._scale.bind("<KeyRelease>", self._scale_change_key)

    def _format_value(self):
        return '{: .2f}'.format(self.value.get())

    def _scale_change_live(self, event):
        self._value_label.configure(text=self._format_value())

    def _scale_change_done(self, event=None):
        self._after_change(self._key, self.value.get())

    def _scale_change_key(self, event):
        if self._change_key_timer:
            self.after_cancel(self._change_key_timer)
        t = 1000
        self._change_key_timer = self.after(t, self._scale_change_done)
© www.soinside.com 2019 - 2024. All rights reserved.