[英]How to prevent property change event loop in kivy?
I have an application acting as a UI for another application through some server. 我有一个应用程序通过某个服务器充当另一个应用程序的UI。 There will be several instances of the UI application.
UI应用程序将有多个实例。 The UI application has a property,
n_property
, representing a parameter of the remote app. UI应用程序具有属性
n_property
,该属性表示远程应用程序的参数。 When n_property
is changed through the UI, it is sent to the server – here simulated through send_value
. 通过UI更改
n_property
,会将其发送到服务器-在这里通过send_value
模拟。 The server passes it on to the application to be controlled, it gets validated there, and passed back to the server. 服务器将其传递给要控制的应用程序,并在那里进行验证,然后传递回服务器。 The server sends the new value back to the UI (and other connected instances of the UI), simulated here with
receive_value
. 服务器将新值发送回UI(以及UI的其他连接实例),在此处使用
receive_value
模拟。
I would like to set n_property
(and the Slider
representing it) to the new value without triggering a new n_property
event , because I do not want to enter an infinite loop of changing values, as happens here when the slider is dragged fast enough. 我想将
n_property
(以及代表它的Slider
)设置为新值而不触发新的n_property
事件 ,因为我不想进入一个不断变化的值循环,就像当滑块被足够快地拖动时那样。
In other frameworks, I'd silence the on change event in receive_value
, but I haven't found an elegant way to do this in kivy [1] . 在其他框架中,我将使
receive_value
的on change事件静音,但是在kivy [1]中还没有找到一种完美的方法来做到这一点。
Here is an example program: 这是一个示例程序:
from kivy.lang import Builder
from kivy.app import App
from kivy.properties import BoundedNumericProperty
from kivy.clock import Clock
class PropApp(App):
n_property = BoundedNumericProperty(5, min=0, max=10)
def build(self):
rw = Builder.load_string("""
GridLayout:
cols:2
Label:
text: "Property Value"
Label:
id: prop_label
text: str(app.n_property)
Label:
text: "Control"
Slider:
id: prop_slider
min: 0
max: 10
value: app.n_property
""")
self.bind(n_property=rw.ids.prop_slider.setter('value'))
rw.ids.prop_slider.bind(value=self.setter('n_property'))
self.bind(n_property=self.send_value)
return rw
def send_value(self, inst, val):
print self.n_property
Clock.schedule_once(lambda dt: self.receive_value(val), .02)
def receive_value(self, val):
self.n_property = val
if __name__ == '__main__':
PropApp().run()
According to the docs, event dispatching is stopped once a handler returns True
, and handlers are called in reverse order of attachment. 根据文档,一旦处理程序返回
True
,事件分发就会停止,并且以相反的顺序调用处理程序。 So I thought changing receive_value
to 所以我想将
receive_value
更改为
def receive_value(self, val):
print "Old value: {} new value: {}".format(self.n_property, val)
def swallow(inst, val):
print "Got swallowed {}".format(val)
inst.funbind('n_property', swallow)
return True
self.fbind('n_property', swallow)
self.n_property = val
would be a clever way to achieve this, and while yes, I don't seem to be able to end up in an infinite loop, there are still a few 'bounces'. 这将是实现此目标的聪明方法,虽然是的,但我似乎无法陷入无限循环,但仍有一些“反弹”。
And it seems that indeed, EventObservers
, which stores the callbacks, is initialized with dispatch_reverse=0
in the definition of Property
, but for events registered with register_event_type
it's dispatch_reverse=1
. 似乎确实,存储回调的
EventObservers
在Property
的定义中使用dispatch_reverse=0
进行了初始化,但是对于使用register_event_type
的事件,则使用dispatch_reverse=1
进行了初始化。
_n_property
, and make n_property
an AliasProperty
whose setter
and getter
access _n_property
.
_n_property
属性,并使n_property
成为一个AliasProperty
其setter
和getter
访问_n_property
。
But that would not be a general solution for the different subclasses of Property
(ie bounds checking for BoundedNumericPropery
or OptionProperty
would have to be separately dealt with).
Property
的不同子类的通用解决方案(即,必须单独处理BoundedNumericPropery
或OptionProperty
边界检查)。
I would use a decorator that stops on_value
method of a slider from being executed too quickly: 我会使用一个装饰器,以
on_value
滑块的on_value
方法执行得太快:
test.kv: test.kv:
#:kivy 1.9.1
GridLayout:
cols: 1
ResponseButton:
text: 'send response from server'
on_press: self.send_response(int(my_input.text), my_slider)
TextInput:
id: my_input
size_hint_y: 0.1
text: '50'
MySlider:
id: my_slider
main.py: main.py:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.slider import Slider
from time import time, sleep
from threading import Thread
from kivy.uix.button import Button
class ResponseButton(Button):
def send_response(self, value, slider):
slider.receive_response(value)
class delayed:
def __init__(self, seconds):
self.seconds = seconds
self.start = time()
self.refused = False
self.function = None
self.args = None
self.run_thread()
def run_thread(self):
def job():
while True:
sleep(self.seconds)
if self.refused and self._time_ok():
self.function(*self.args)
self.refused = False
thread = Thread(target=job)
thread.daemon = True
thread.start()
def _time_ok(self):
return time() - self.start > self.seconds
def __call__(self, function):
self.function = function
def decorated(*args):
self.args = args
if self._time_ok():
self.start = time()
function(*self.args)
else:
self.refused = True
return decorated
class MySlider(Slider):
_call_server = True
def receive_response(self, value):
print '@@@ received from server:', value
self._call_server = False
self.value = value
@delayed(seconds=2)
def on_value(self, obj, value):
if self._call_server:
self.send_value(value)
else:
self._call_server = True
def send_value(self, value):
print '>>> sent value to server:', value
class Test(App):
pass
Test().run()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.