如何从文件中的变量项创建功能按钮 Python Kivy APP
How to create function buttons from variable items in a file Python Kivy APP
我实际上正在尝试创建一个应用程序,但我遇到了一个大问题
具体来说,它应该检查一个装满图片的文件夹中的项目,并且应该为每个项目在 Scollview GridLayout 列表中创建一个 ImageButton(已定义)。目前有效..
但是当其中一张显示的图片被按下时,我想让它改变主屏幕上图片的路径
这是我的Python代码
#This is outside the MDApp class
class ImageButton(ButtonBehavior, Image):
#Inside the MDApp class
def item_choser(self, item)
.
.
.
elif item == "car":
#It first clears the grid layout
self.root.ids.pictures_grid.clear_widgets()
#Then, the path folder of the items(pictures) is being defined
pictures = glob.glob(f"./images/items/cars/*.jpg")
#For loop created to assign
for i in pictures:
#This "z" is the number after path in format <path_test_golf7_tez.jpg>
#Different for every picture (01, 02, 03 etc)
z = i[-21:-19]
#Creating button with bind
z = ImageButton(source=i, allow_stretch=True, keep_ratio=True)
z.bind(on_release=lambda x:self.chosen(i)) <<--- Here is my actual problem
print(z)
#Adding it into the grid
self.root.ids.pictures_grid.add_widget(z)
def chosen(self, selectedCar):
print(selectedCar)
self.root.ids.main_image_display.source = selectedCar
这是路径文件夹包含的内容:
...cars_test_golf8_tez.jpg
...cars_test_golf7_tez.jpg
...cars_test_passat_te.jpg
...cars_test_crafter_t.jpg
所有照片都摆放正确。对于绑定后打印的每个“ z ”,它在内存中显示一个不同的对象,所以直到这里一切都很好
但这就是我的问题开始的地方。
假设你想选择帕萨特,所以你按下它的图片,但不知何故,无论你按下什么图片,chosen 函数总是会打印“...cars_test_crafter_t.jpg
如何编写此代码才能将 1 个按钮绑定到它的功能?
这是找到的最接近的答案,但要么我不明白如何在我的代码中使用和集成它,要么它根本无济于事 [lambda x, i=i : i * x for i in range( len(pictures))] 因为它不起作用
这可能不是完整的答案,但我不能在评论中挤出太多代码。
制作 gala
列表,然后将每张图片附加到其中:
gala = []
for i in pictures:
z = i[-21:-19]
tmp = ImageButton(source=i, allow_stretch=True, keep_ratio=True)
tmp.bind(on_release=lambda x, i=i:self.chosen(i)) # closure hack
self.root.ids.pictures_grid.add_widget(tmp)
gala.append(tmp) # can reference later > gala[0]
关于'hack'
目标函数 (lamda) 不会立即 运行。定义函数时,python使用后期绑定。这样,python 存储了方法地址(lambda)和参数地址(i)。它不存储参数值。稍后调用该函数时,将使用参数变量的当前(最新)值。
举个例子。当调用 chosen
时,i
将等于 2,因为这是循环完成但实际调用函数之前 i
的值。
for i in range(3): 0-2
tmp.bind(on_release=lambda i:self.chosen(i)) # address of i is stored, not value
黑客通过强制提前绑定解决了这个问题。使用 i=i
告诉 python 该参数有一个默认值(如 def myfunc(i=5)
)并且应该使用早期绑定。使用早期绑定,(默认)参数值在创建方法时存储,解决了循环问题。
for i in range(3): 0-2
tmp.bind(on_release=lambda x, i=i:self.chosen(i)) # value of i is stored
可能不需要 x
参数。您可以通过实验来确认。
@inclement 在他的评论中提供了有用的 link:https://docs.python-guide.org/writing/gotchas/#late-binding-closures
我认为问题出在 ImageButton Class - 您需要检查那里是否确实按下了那个按钮。
class ImageButton(Button):
# ....
def on_touch_down(self, touch):
"""
Check which of the buttons was pressed
:param touch:
:return:
"""
if self.collide_point(*touch.pos):
print(self.source)
# You could then trigger an event from here and pass the Source/ID whatever as parameter
else:
# This Button wasn't pressed
pass
您可以使用 on_touch_down 函数的 touch
参数进行检查。检查 touch.pos
与哪个按钮碰撞器发生碰撞。 on_touch_down
事件会为所有 ImageButton 触发,即使只按下一个!
我总是使用按钮 ID 来识别按钮 - link 具有更多数据。
我实际上正在尝试创建一个应用程序,但我遇到了一个大问题
具体来说,它应该检查一个装满图片的文件夹中的项目,并且应该为每个项目在 Scollview GridLayout 列表中创建一个 ImageButton(已定义)。目前有效..
但是当其中一张显示的图片被按下时,我想让它改变主屏幕上图片的路径
这是我的Python代码
#This is outside the MDApp class
class ImageButton(ButtonBehavior, Image):
#Inside the MDApp class
def item_choser(self, item)
.
.
.
elif item == "car":
#It first clears the grid layout
self.root.ids.pictures_grid.clear_widgets()
#Then, the path folder of the items(pictures) is being defined
pictures = glob.glob(f"./images/items/cars/*.jpg")
#For loop created to assign
for i in pictures:
#This "z" is the number after path in format <path_test_golf7_tez.jpg>
#Different for every picture (01, 02, 03 etc)
z = i[-21:-19]
#Creating button with bind
z = ImageButton(source=i, allow_stretch=True, keep_ratio=True)
z.bind(on_release=lambda x:self.chosen(i)) <<--- Here is my actual problem
print(z)
#Adding it into the grid
self.root.ids.pictures_grid.add_widget(z)
def chosen(self, selectedCar):
print(selectedCar)
self.root.ids.main_image_display.source = selectedCar
这是路径文件夹包含的内容:
...cars_test_golf8_tez.jpg
...cars_test_golf7_tez.jpg
...cars_test_passat_te.jpg
...cars_test_crafter_t.jpg
所有照片都摆放正确。对于绑定后打印的每个“ z ”,它在内存中显示一个不同的对象,所以直到这里一切都很好
但这就是我的问题开始的地方。
假设你想选择帕萨特,所以你按下它的图片,但不知何故,无论你按下什么图片,chosen 函数总是会打印“...cars_test_crafter_t.jpg
如何编写此代码才能将 1 个按钮绑定到它的功能?
这是找到的最接近的答案,但要么我不明白如何在我的代码中使用和集成它,要么它根本无济于事 [lambda x, i=i : i * x for i in range( len(pictures))] 因为它不起作用
这可能不是完整的答案,但我不能在评论中挤出太多代码。
制作 gala
列表,然后将每张图片附加到其中:
gala = []
for i in pictures:
z = i[-21:-19]
tmp = ImageButton(source=i, allow_stretch=True, keep_ratio=True)
tmp.bind(on_release=lambda x, i=i:self.chosen(i)) # closure hack
self.root.ids.pictures_grid.add_widget(tmp)
gala.append(tmp) # can reference later > gala[0]
关于'hack'
目标函数 (lamda) 不会立即 运行。定义函数时,python使用后期绑定。这样,python 存储了方法地址(lambda)和参数地址(i)。它不存储参数值。稍后调用该函数时,将使用参数变量的当前(最新)值。
举个例子。当调用 chosen
时,i
将等于 2,因为这是循环完成但实际调用函数之前 i
的值。
for i in range(3): 0-2
tmp.bind(on_release=lambda i:self.chosen(i)) # address of i is stored, not value
黑客通过强制提前绑定解决了这个问题。使用 i=i
告诉 python 该参数有一个默认值(如 def myfunc(i=5)
)并且应该使用早期绑定。使用早期绑定,(默认)参数值在创建方法时存储,解决了循环问题。
for i in range(3): 0-2
tmp.bind(on_release=lambda x, i=i:self.chosen(i)) # value of i is stored
可能不需要 x
参数。您可以通过实验来确认。
@inclement 在他的评论中提供了有用的 link:https://docs.python-guide.org/writing/gotchas/#late-binding-closures
我认为问题出在 ImageButton Class - 您需要检查那里是否确实按下了那个按钮。
class ImageButton(Button):
# ....
def on_touch_down(self, touch):
"""
Check which of the buttons was pressed
:param touch:
:return:
"""
if self.collide_point(*touch.pos):
print(self.source)
# You could then trigger an event from here and pass the Source/ID whatever as parameter
else:
# This Button wasn't pressed
pass
您可以使用 on_touch_down 函数的 touch
参数进行检查。检查 touch.pos
与哪个按钮碰撞器发生碰撞。 on_touch_down
事件会为所有 ImageButton 触发,即使只按下一个!
我总是使用按钮 ID 来识别按钮 - link 具有更多数据。