Home > Enterprise >  Python - adding pictures and commands behind dynamic buttons
Python - adding pictures and commands behind dynamic buttons

Time:02-15

I am quite new to python and RPi. I am trying to generate dynamic buttons based on a MySQL Query. I found this thread in the forum: How to create a self resizing grid of buttons in tkinter?

It was helpful to understand how to generate dynamic buttons in a grid. Nevertheless, I am having issues putting commands for each dynamic button and picture.

This is my code:

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

The issue is, when I run the code, it shows the picture only on the last Button, and also the command behind the buttons does not work.

If I define the picture before the For LOOP, it works at least with all the same pictures on each button.

Any idea, what I am doing wrong?

CodePudding user response:

command=CocktailBtnCmd(CocktailID) will execute CocktailBtnCmd(...) immediately and assign the result (which is None) to command option. That is why the button does not work later.

You need to use lambda using argument with default value instead:

command=lambda CocktailID=CocktailID: CocktailBtnCmd(CocktailID)

For the image issue, it is because you have used same variable to hold the reference of the images in the for loop:

photoImage = btn_image.subsample(2, 2)

So after the for loop, only the last image has reference to it and the previous ones will be garbage collected.

You can keep references of all the images using attribute of the related buttons:

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
    ...

Also I would recommend to use the official mysql.connector module instead of MySQLdb.

  • Related