Python - 在动态按钮后面添加图片和命令

Python - adding pictures and commands behind dynamic buttons

我对 python 和 RPi 很陌生。我正在尝试根据 MySQL 查询生成动态按钮。我在论坛中找到了这个帖子:How to create a self resizing grid of buttons in tkinter?

了解如何在网格中生成动态按钮很有帮助。尽管如此,我在为每个动态按钮和图片输入命令时遇到问题。

这是我的代码:

from __future__ import division
import tkinter  as tk
from tkinter import *

import MySQLdb
db = MySQLdb.connect("localhost", "User...", "SecurePW", "myCoolDB")
curs=db.cursor()

PhotoImageFolder='/home/pi/App/CocktailPic/'

root = Tk()
Grid.rowconfigure(root, 0, weight=1)
Grid.columnconfigure(root, 0, weight=1)

#Create & Configure frame 
frame=Frame(root)
frame.grid(row=0, column=0, sticky=N+S+E+W)

curs.execute("SELECT * FROM `CockRec` WHERE `IsACTIVE`=1")

max_col_index=10
col_index=0
row_index=0

def CocktailBtnCmd(Cocktail_ID):
    messagebox.showinfo(title='Informatio', message=Cocktail_ID)
    #print("Cocktail ID: ",Cocktail_ID)
    
for entry in curs.fetchall():   
    if col_index>=max_col_index:
        row_index=row_index+1
        col_index=0
    CocktailID=entry[0]
    Cocktail=entry[1]
    CocktailPicturePath=entry[3]
    btn_image=PhotoImage(file = PhotoImageFolder + CocktailPicturePath)
    photoImage = btn_image.subsample(10, 10)
    Grid.rowconfigure(frame, row_index, weight=1)
    Grid.columnconfigure(frame, col_index, weight=1)
    btn = Button(frame, text = Cocktail, image=photoImage, command = CocktailBtnCmd(CocktailID)) #create a button
    btn.grid(row=row_index, column=col_index, sticky=N+S+E+W)
    col_index=col_index+1

问题是,当我 运行 代码时,它只在最后一个按钮上显示图片,而且按钮后面的命令不起作用。

如果我在 For LOOP 之前定义图片,它至少适用于每个按钮上的所有相同图片。

知道吗,我做错了什么?

command=CocktailBtnCmd(CocktailID) 将立即执行 CocktailBtnCmd(...) 并将结果(即 None)分配给 command 选项。这就是按钮稍后不起作用的原因。

您需要使用 lambda 使用默认值的参数来代替:

command=lambda CocktailID=CocktailID: CocktailBtnCmd(CocktailID)

图片问题,是因为你在for循环中使用了相同的变量来保存图片的引用:

photoImage = btn_image.subsample(2, 2)

所以在for循环之后,只有最后一张图片引用了它,之前的图片将被垃圾回收。

您可以使用相关按钮的属性保留所有图像的引用:

for entry in curs.fetchall():
    ...
    photoImage = btn_image.subsample(2, 2)
    ...
    btn = Button(frame, text = Cocktail, image=photoImage, command=lambda: CocktailID=CocktailID: CocktailBtnCmd(CocktailID))
    btn.image = photoImage # use an attribute to keep the reference of image
    ...

此外,我建议使用官方 mysql.connector 模块而不是 MySQLdb