按钮上的绑定在 Kivy 中令人困惑
The binding on button is confusing in Kivy
作为测试,我准备了以下代码,
首先,我从两个函数名称 add_front
和 add_back
设置按钮文本
然后,我从名称中获取函数句柄,并创建一个部分函数将其绑定到 Buttons。
虽然绑定看起来没问题,但结果是随机的。
有人能帮帮我吗?
"""
@author:
@file:test-bind.py
@time:2022/01/3111:42
@file_desc
"""
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.clock import Clock
import random
from functools import partial
Builder.load_string("""
<MButton@Button>:
_cb:[]
<TestWin>:
inp1:inp1_
lbl1:lbl1_
btn1:btn1_
btn2:btn2_
orientation: 'vertical'
BoxLayout:
orientation:'horizontal'
TextInput:
id:inp1_
readonly: True
Label:
id:lbl1_
MButton:
id:btn1_
text: 'add_front'
MButton:
id:btn2_
text: 'add_back'
Button:
id:btn_cls_
text:'clear'
on_press:root.clear_elements()
Button:
id:btn_shuffle_
text:'Shuffle'
on_press:root.shuffle_btn()
TextInput:
multiline: True
text:'Usage: press <Shuffle> to randomize button function and set a random number in [0,9], press <add_front> or <add_back> buttons to insert to list'
""")
class Box:
def __init__(self):
self.elements =[]
def add(self,e,front=False):
if front:
self.elements.insert(0,e)
else:
self.elements.append(e)
def add_front(self,e):
print("add_front",e)
self.add(e,front=True)
def add_back(self,e):
print("add_back",e)
self.add(e,front=False)
class TestWin(BoxLayout):
inp1 = ObjectProperty()
lbl1 = ObjectProperty()
btn1 = ObjectProperty()
btn2 = ObjectProperty()
btn_bind = ObjectProperty()
def __init__(self, **kwargs):
super(TestWin, self).__init__(**kwargs)
self.box = Box()
Clock.schedule_interval(self.update_elements_display, 0.5)
def update_elements_display(self,*args):
self.lbl1.text = "%s"%str(self.box.elements)
pass
def clear_elements(self):
self.box.elements=[]
def shuffle_btn(self):
btn_txt_ = ["add_front", "add_back"]
random.shuffle(btn_txt_)
self.btn1.text = btn_txt_[0]
self.btn2.text = btn_txt_[1]
v = random.randint(0,9)
self.inp1.text= "%d"%v
# bind func
for btn in [self.btn1,self.btn2]:
# clear old bind firstly
for cb in btn._cb:
btn.funbind("on_press",cb)
btn._cb = []
# The following codes give wrong result
#foo_ = getattr(self.box, btn.text)
#foo = lambda elem, instance: foo_(elem)
#call_back_ = partial(foo, self.inp1.text)
# The following codes give correct result
if btn.text=="add_back":
call_back_ = partial(self.box.add_back, self.inp1.text)
elif btn.text =="add_front":
call_back_ = partial(self.box.add_front, self.inp1.text)
btn._cb.append(call_back_)
btn.fbind('on_press',call_back_)
print("bind to",call_back_)
class TestApp(App):
def build(self):
return TestWin()
if __name__ == '__main__':
TestApp().run()
编辑:
修改以下代码可能会给我正确的结果,
但我想知道为什么
# The following codes give wrong result
#foo_ = getattr(self.box, btn.text)
#foo = lambda elem, instance: foo_(elem)
#call_back_ = partial(foo, self.inp1.text)
# The following codes give correct result
if btn.text=="add_back":
call_back_ = partial(self.box.add_back, self.inp1.text)
elif btn.text =="add_front":
call_back_ = partial(self.box.add_front, self.inp1.text)
# The following doesn't work
# foo_ = getattr(self.box, btn.text)
# foo = lambda elem, instance: foo_(elem)
# call_back_ = partial(foo, self.inp1.text)
#this is ok
call_back_ = partial(getattr(self.box, btn.text), self.inp1.text)
作为测试,我准备了以下代码,
首先,我从两个函数名称 add_front
和 add_back
然后,我从名称中获取函数句柄,并创建一个部分函数将其绑定到 Buttons。
虽然绑定看起来没问题,但结果是随机的。
有人能帮帮我吗?
"""
@author:
@file:test-bind.py
@time:2022/01/3111:42
@file_desc
"""
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.clock import Clock
import random
from functools import partial
Builder.load_string("""
<MButton@Button>:
_cb:[]
<TestWin>:
inp1:inp1_
lbl1:lbl1_
btn1:btn1_
btn2:btn2_
orientation: 'vertical'
BoxLayout:
orientation:'horizontal'
TextInput:
id:inp1_
readonly: True
Label:
id:lbl1_
MButton:
id:btn1_
text: 'add_front'
MButton:
id:btn2_
text: 'add_back'
Button:
id:btn_cls_
text:'clear'
on_press:root.clear_elements()
Button:
id:btn_shuffle_
text:'Shuffle'
on_press:root.shuffle_btn()
TextInput:
multiline: True
text:'Usage: press <Shuffle> to randomize button function and set a random number in [0,9], press <add_front> or <add_back> buttons to insert to list'
""")
class Box:
def __init__(self):
self.elements =[]
def add(self,e,front=False):
if front:
self.elements.insert(0,e)
else:
self.elements.append(e)
def add_front(self,e):
print("add_front",e)
self.add(e,front=True)
def add_back(self,e):
print("add_back",e)
self.add(e,front=False)
class TestWin(BoxLayout):
inp1 = ObjectProperty()
lbl1 = ObjectProperty()
btn1 = ObjectProperty()
btn2 = ObjectProperty()
btn_bind = ObjectProperty()
def __init__(self, **kwargs):
super(TestWin, self).__init__(**kwargs)
self.box = Box()
Clock.schedule_interval(self.update_elements_display, 0.5)
def update_elements_display(self,*args):
self.lbl1.text = "%s"%str(self.box.elements)
pass
def clear_elements(self):
self.box.elements=[]
def shuffle_btn(self):
btn_txt_ = ["add_front", "add_back"]
random.shuffle(btn_txt_)
self.btn1.text = btn_txt_[0]
self.btn2.text = btn_txt_[1]
v = random.randint(0,9)
self.inp1.text= "%d"%v
# bind func
for btn in [self.btn1,self.btn2]:
# clear old bind firstly
for cb in btn._cb:
btn.funbind("on_press",cb)
btn._cb = []
# The following codes give wrong result
#foo_ = getattr(self.box, btn.text)
#foo = lambda elem, instance: foo_(elem)
#call_back_ = partial(foo, self.inp1.text)
# The following codes give correct result
if btn.text=="add_back":
call_back_ = partial(self.box.add_back, self.inp1.text)
elif btn.text =="add_front":
call_back_ = partial(self.box.add_front, self.inp1.text)
btn._cb.append(call_back_)
btn.fbind('on_press',call_back_)
print("bind to",call_back_)
class TestApp(App):
def build(self):
return TestWin()
if __name__ == '__main__':
TestApp().run()
编辑: 修改以下代码可能会给我正确的结果, 但我想知道为什么
# The following codes give wrong result
#foo_ = getattr(self.box, btn.text)
#foo = lambda elem, instance: foo_(elem)
#call_back_ = partial(foo, self.inp1.text)
# The following codes give correct result
if btn.text=="add_back":
call_back_ = partial(self.box.add_back, self.inp1.text)
elif btn.text =="add_front":
call_back_ = partial(self.box.add_front, self.inp1.text)
# The following doesn't work
# foo_ = getattr(self.box, btn.text)
# foo = lambda elem, instance: foo_(elem)
# call_back_ = partial(foo, self.inp1.text)
#this is ok
call_back_ = partial(getattr(self.box, btn.text), self.inp1.text)