如何限制widget生成的事件数量 [英] How to limit the number of events generated by 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屋!