如何从文件Python Kivy应用程序中的变量项创建函数按钮

如何从文件Python Kivy应用程序中的变量项创建函数按钮,python,python-3.x,kivy,kivy-language,kivymd,Python,Python 3.x,Kivy,Kivy Language,Kivymd,我实际上正在尝试创建一个应用程序,但遇到了一个大问题 具体来说,它应该检查一个包含图片的文件夹中的项目,并为每个项目在Scollview GridLayout列表中创建一个ImageButton(已定义)。到目前为止还有效 但当按下其中一张显示的图片时,我希望它改变主屏幕上图片的路径 这是我的Python代码 #This is outside the MDApp class class ImageButton(ButtonBehavior, Image): #Inside the MDApp

我实际上正在尝试创建一个应用程序,但遇到了一个大问题

具体来说,它应该检查一个包含图片的文件夹中的项目,并为每个项目在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\02_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

#这不属于MDApp类
类ImageButton(按钮行为,图像):
#在MDApp类中
def项目(自身、项目)
.
.
.
elif项目==“汽车”:
#它首先清除网格布局
self.root.ids.pictures\u grid.clear\u widgets()
#然后,定义项目(图片)的路径文件夹
图片=glob.glob(f.“/images/items/cars/*.jpg”)
#用于创建要分配的循环
对于图片中的我:
#此“z”是格式中路径后的数字
#每幅图片都不同(01、02、03等)
z=i[-21:-19]
#使用绑定创建按钮
z=ImageButton(源=i,允许拉伸=True,保持比率=True)

z、 bind(on_release=lambda x:self.selected(i))这可能不是完整的答案,但我无法在注释中压缩太多代码

制作
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]
关于“黑客”

目标函数(lamda)不会立即运行。定义函数时,python使用后期绑定。这样,python存储方法地址(lambda)和参数地址(i)。它不存储参数的值。稍后调用该函数时,将使用参数变量的当前(最新)值

就拿这个例子来说。调用
selected
时,
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
参数。你可以通过实验来确认


@恶劣天气在他的评论中提供了一个有用的链接:

我假设问题出在ImageButton类中-您需要在那里检查按钮是否被按下

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
您可以使用该功能的
touch
参数进行检查。检查
touch.pos
与哪个按钮碰撞。即使只按下一个按钮,所有图像按钮都会触发
on\u touch\u down
事件


我总是使用按钮id来标识按钮,并将其与更多数据链接。

在循环中创建函数时遇到了一个常见问题,请参阅。此语法导致错误:
gala+z=…
gala
应该是一个集合吗?@Mike67-不,它们应该是变量,我想在其末尾添加不同的数字,这样它们就可以不同,以便绑定正常工作。@谢谢您的反馈。你发送的URL实际上有帮助,但我不明白它是如何工作的,所以我无法在代码中实现它(你可以在我的主要问题的最后一行中看到)…你好,有趣的想法,但我认为它在我的情况下不起作用,因为我的ImageButton类不是应用程序的一部分,所以它不知道self function Plus,我的按钮的继承有点不同:类ImageButton(ButtonBehavior,Image):起初我不理解您所说的,但现在它有了意义。尽管如此,在创建列表后,我打印了它,实际上它在内存中显示了4个不同的项目。但当按下第一张图片时,它仍然显示“所选”功能中的最后一个。我仍在试图理解“黑客”是如何工作的,因为对我来说,这毫无意义。。。但那东西行得通!非常感谢你的帮助!非常感谢你,迈克!确切地说,我试图理解@increment中的示例,但我不确定如何在代码中实现它,因为它没有意义。