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
.