如何限制widget生成的事件数量 [英] How to limit the number of events generated by widget

查看:33
本文介绍了如何限制widget生成的事件数量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用旋转框实时控制字体大小,以实现缩放效果.Spinbox 小部件可以生成很多事件.只要您按住键盘上的方向键或单击并按住方向小部件箭头图标之一,事件就会由旋转框生成.
问题是我要参加很多活动,这使缩放效果挂起.我已经设置了一个演示,使用两个不同的 spinboxes,一个 tk.Spinbox 和一个 ttk.Spinbox.使用th tk.Spinbox,您可以使用repeatdelay 和repeatinterval"来限制速率,这确实有效,它仅在您单击spinbox 中的箭头按钮之一时有效.如果您按向上或向下键,尽管repeatdelay 和repeatinterval"不起作用.至于 ttk.Spinbox 它除了参数repeatdelay 和repeatinterval"之外没有,所以它对它没有影响.如何限制两种类型的旋转框的重复率?

I'm using a spinbox to control the size of fonts in real time, for a zooming effect. A spinbox widget can generate a lot of events. As long as you hold down a direction key on the keyboard or click and hold down one the direction widget arrow icons, events get generated by the spinbox.
The problem is I'm getting to many events and this is making the zoom effect hang. I have setup a demo showing this using two different spinboxes, a tk.Spinbox and a ttk.Spinbox. With th tk.Spinbox you can limit the rate using "repeatdelay and repeatinterval" well this does work it only works when you click one of the arrow buttons in the spinbox. If you press the up or down keys though the "repeatdelay and repeatinterval" has no effect. As for the ttk.Spinbox it doesn't except the parameters "repeatdelay and repeatinterval" so it has no effect on it. How can I limit the repeat rate for both type of spinboxes?

import tkinter as tk
import tkinter.ttk as ttk


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.rowconfigure(990, weight=1)
        self.columnconfigure(0, weight=1)
        self.title('Timed Events Demo')
        self.geometry('420x200+20+20')

        tk_spn = tk.Spinbox(
            self,
            value=0,
            from_=0, to=1000,
            repeatdelay=500,
            repeatinterval=500,
            values=list(range(0, 1000))
        )
        tk_spn.grid(row=0, pady=5)

        tk_spn = ttk.Spinbox(
            self,
            from_=0, to=1000,
            value=0,
            values=list(range(0, 1000))
        )
        tk_spn.grid(row=1, pady=5)

        self.cnt = 0

        def test(e):
            print(self.cnt, e)

        tk_spn.bind('<<Increment>>', test)


def main():
    app = App()
    app.mainloop()


if __name__ == '__main__':
    main()

推荐答案

我对两种类型的 spinbox 使用了类似的解决方案,但实现有点不同,因为它们不使用相同的事件.这个想法是创建一个带有 _increment_lock 属性的 Spinbox 类,当 Spinbox 递增并在延迟后设置回 False 时,该属性设置为 True.然后,增加 spinbox 的事件绑定到一个方法,该方法在实际执行增量之前检查 _increment_lock.递减的原理是一样的.

I used similar solutions for both kinds of spinboxes but the implementation is a bit different since they don't use the same events. The idea is to create a Spinbox class with an _increment_lock attribute which is set to True when the Spinbox is incremented and after a delay is set back to False. Then, the events that increment the spinbox are bound to a method that checks _increment_lock before actually performing the increment. The principle is the same for the decrement.

对于 tk.Spinbox,我使用了 箭头的绑定来实现上述当我使用 <><<> 绑定时的解决方案.

For the tk.Spinbox, I used the bindings to the <Up> and <Down> arrows to implement the above solution while I used the bindings to <<Increment>> and <<Decrement>>.

代码如下:

import tkinter as tk
import tkinter.ttk as ttk


class MySpinbox(tk.Spinbox):
    def __init__(self, master=None, delay=500, **kwargs):
        kwargs.setdefault('repeatdelay', delay)
        kwargs.setdefault('repeatinterval', delay)
        tk.Spinbox.__init__(self, master, **kwargs)
        self.delay = delay  # repeatdelay in ms
        self.bind('<Up>', self._on_increment)
        self.bind('<Down>', self._on_decrement)
        self._increment_lock = False
        self._decrement_lock = False

    def _unlock_increment(self):
        self._increment_lock = False

    def _on_increment(self, event):
        if self._increment_lock:
            return "break"  # stop the increment
        else:
            self._increment_lock = True
            self.after(self.delay, self._unlock_increment)

    def _unlock_decrement(self):
        self._decrement_lock = False

    def _on_decrement(self, event):
        if self._decrement_lock:
            return "break"  # stop the increment
        else:
            self._decrement_lock = True
            self.after(self.delay, self._unlock_decrement)


class MyTtkSpinbox(ttk.Spinbox):
    def __init__(self, master=None, delay=500, **kwargs):
        ttk.Spinbox.__init__(self, master, **kwargs)
        self.delay = delay  # repeatdelay in ms
        self.bind('<<Increment>>', self._on_increment)
        self.bind('<<Decrement>>', self._on_decrement)
        self._increment_lock = False
        self._decrement_lock = False

    def _unlock_increment(self):
        self._increment_lock = False

    def _on_increment(self, event):
        if self._increment_lock:
            return "break"  # stop the increment
        else:
            # generate a virtual event corresponding to when the spinbox
            # is actually incremented
            self.event_generate('<<ActualIncrement>>')
            self._increment_lock = True
            self.after(self.delay, self._unlock_increment)

    def _unlock_decrement(self):
        self._decrement_lock = False

    def _on_decrement(self, event):
        if self._decrement_lock:
            return "break"  # stop the increment
        else:
            # generate a virtual event corresponding to when the spinbox
            # is actually decremented
            self.event_generate('<<ActualDecrement>>')
            self._decrement_lock = True
            self.after(self.delay, self._unlock_decrement)


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.rowconfigure(990, weight=1)
        self.columnconfigure(0, weight=1)
        self.title('Timed Events Demo')
        self.geometry('420x200+20+20')

        tk_spn1 = MySpinbox(self, value=0, values=list(range(0, 1000)))
        tk_spn1.grid(row=0, pady=5)

        tk_spn2 = MyTtkSpinbox(self, from_=0, to=1000)
        tk_spn2.grid(row=1, pady=5)

        def test(e):
            print(e)

        tk_spn2.bind('<<ActualIncrement>>', test)


if __name__ == '__main__':
    app = App()
    app.mainloop()

这篇关于如何限制widget生成的事件数量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆