0

Just to get this clear before I begin.

I have the same problem as outlined in this question: Tkinter: creating an arbitrary number of buttons/widgets

but the accepted answer doesn't work for me.

This is my code:

import os
try:
    from tkinter import *
except ImportError:
    from Tkinter import *

from subprocess import call

root = Tk()
root.wm_attributes("-fullscreen", "true")
root.config(background = "#FFFFFF")

backIMG = PhotoImage(file="b.gif")
usbIMG = PhotoImage(file="u.gif")
usbAuswahlIMG = PhotoImage(file="ua.gif")
downloadsIMG = PhotoImage(file="d.gif")
downloadsAuswahlIMG = 
PhotoImage(file="da.gif")

menuFrame = Frame(root, width=200, height=600, bg="#FFFF00")
menuFrame.grid(row=0, column=0, padx=10, pady=3)

def goBack():
    #os.system('python gui.py')
    root.destroy()

def selectUSB():
    downloadsButton.config(image=downloadsIMG)
    usbButton.config(image=usbAuswahlIMG)



def selectDownloads():
    usbButton.config(image=usbIMG) 
    downloadsButton.config(image=downloadsAuswahlIMG)
    i = 0
    buttons = dict()
    for file in os.listdir('/home/pi/Downloads'):
        if file.endswith(".mp3") or file.endswith(".wav"):
            buttons[i] = Button(contentFrame, text=file, width=60, font=("Sans", 15), command=lambda a=i: playDL(a).grid(row=i, column=0))
            i = i + 1
            print()

def playDL(index):
    print (index)

usbButton = Button(menuFrame, image=usbIMG, 
command=selectUSB)
usbButton.pack()

downloadsButton = Button(menuFrame, image=downloadsIMG, 
command=selectDownloads)
downloadsButton.pack()

stopButton = Button(menuFrame, image=backIMG, 
command=goBack)
stopButton.pack()

contentFrame = Frame(root, width=760, height=594, bg='#FFFFFF')
contentFrame.grid(row=0, column=1, padx=13, pady=3)

root.mainloop()

On the other post, one suggested, to add this code here:

buttons = dict()
for k in range(len(info)):
    buttons[k] = Button(top, text=info[k], command=lambda a=k: my_function(buttons[a]))

which I've done and changed it up here and there to fit my code.

The problem is that now the buttons don't show up on the content Frame at all. It still runs though the loop but no buttons to be seen. At first I just had this:

for file in os.listdir('/home/pi/Downloads'):
        if file.endswith(".mp3") or file.endswith(".wav"):
            Button(contentFrame, text=file, width=60, font=("Sans", 15), command=lambda: playDL(i).grid(row=i, column=0))
            i = i + 1

and all the buttons did the same nothingeness, but were visible.

I started programming in python yesterday but i am quiet familiar with Java and Visual C# so I have a basic understandment of what I'm doing (sort of)

ChrisF
  • 134,786
  • 31
  • 255
  • 325

1 Answers1

1

Change this:

for file in os.listdir('/home/pi/Downloads'):
        if file.endswith(".mp3") or file.endswith(".wav"):
            Button(contentFrame, text=file, width=60, font=("Sans", 15),
            command=lambda: playDL(i).grid(row=i, column=0))
            i = i + 1

To this:

for file in os.listdir('/home/pi/Downloads'):
        if file.endswith(".mp3") or file.endswith(".wav"):
            Button(contentFrame, text=file, width=60, font=("Sans", 15),
            command=lambda i=i: playDL(i)).grid(row=i, column=0)
            i = i + 1

You placed your grid manage inside of your lambda function instead of outside the button widget.

As tobias pointed out in the comments you need to use i=i in your lambda in order for your values to be accurate for each button or all of them will have the last value in the loop.

Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • This fixes part of the problem, but you still have the "lambda in a loop" issue. Use `lambda i=i` to bind the current value of `i` to the `i` in the lambda (instead of value that's current when the lambda is evaluated) – tobias_k Nov 13 '18 at 13:18
  • Jesus Christ how could I have missed that? >~< Thanks a lot! – Akarui Kage Nov 13 '18 at 13:20
  • @tobias_k thanks I will add that. I was only focused on the issue of the button not showing up but that part is important as well. – Mike - SMT Nov 13 '18 at 13:32
  • It would be better if you move the `.grid(...)` to a separate statement. It makes the code easier to read, and reinforces a good habit. – Bryan Oakley Nov 13 '18 at 17:03
  • @BryanOakley I normally never use variable names on widgets that will not be accessed later in the code. For me it makes the code easier to read as it lets one know that this widget is set up in a way that we do not expect to edit it later or need to pull information from it directly. I do understand the standpoint of moving the grid to a new line if you want to use a variable name to assist with readability as far as know what that widget is for. What benefit is there to moving the grid to a new line here? For me it seams like there is none. – Mike - SMT Nov 13 '18 at 17:10
  • @Mike-SMT: to me, widget creation and widget layout are two separate things. In this specific case it's not that big of a deal, but I think code is much easier to write, read, and maintain when all of the layout code is grouped together for a given parent. Also, being in that habit would have 100% prevented this particular bug. I think the consistency of always doing it the same way (create widget first, then layout as a group later) is more important than saving a few lines of code. – Bryan Oakley Nov 13 '18 at 17:14
  • @BryanOakley When you say all of the layout code is grouped do you mean all of the layout code group with its widget on the next line or all of the layout code grouped after all the widgets have been made? I have used both ways and still on the fence on what reads better. – Mike - SMT Nov 13 '18 at 17:15
  • @Mike-SMT: after you've created all the widgets. Seeing grid calls interlaced with widget creation is the worst possible way to do it in my opinion. In my experience, you tend to fiddle with the layout a lot more than the options of the widget itself. Having it all grouped makes it much easier to visualize the layout, and to tweak the layout during development. – Bryan Oakley Nov 13 '18 at 17:38
  • @BryanOakley That makes sense. I will keep that in mind for future post. Thanks for the insight, it is always appreciated. – Mike - SMT Nov 13 '18 at 17:41