我有一个应用程序通过某个服务器充当另一个应用程序的UI。将有几个UI应用程序实例。 UI应用程序具有属性n_property
,表示远程应用程序的参数。通过用户界面更改n_property
时,会将其发送到服务器 - 此处通过send_value
进行模拟。服务器将其传递给要控制的应用程序,它在那里得到验证,然后传回服务器。服务器将新值发送回UI(以及UI的其他连接实例),此处使用receive_value
进行模拟。
我想将n_property
(以及代表它的Slider
设置为新值,而不会触发新的n_property
事件,因为我不知道想要进入一个无限循环的变化值,就像滑动拖动得足够快时一样。
在其他框架中,我会在receive_value
中对变更事件进行沉默,但我还没有找到一种优雅的方法来实现这一点
以下是一个示例程序:
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()
根据文档,一旦处理程序返回True
,事件调度就会停止,并且处理程序会以相反的顺序被调用。
所以我想把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
将是一种聪明的方法来实现这一点,虽然是的,我似乎无法以无限循环结束,仍然有一些“反弹”。
似乎确实存储回调的EventObservers
在dispatch_reverse=0
的定义中使用Property
初始化,但对于使用register_event_type
注册的事件,它是{ {1}}。
<小时/> [1] 我想我可以拥有一个属性
dispatch_reverse=1
,并使_n_property
成为n_property
AliasProperty
和setter
访问{ {1}}。但这不是getter
的不同子类的一般解决方案(即必须单独处理_n_property
或Property
的边界检查。)
答案 0 :(得分:1)
我会使用一个装饰器来阻止滑块的on_value
方法执行得太快:
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:
#!/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()