Placing Images in loop in Tkinter - python

I'm trying to place a set of images in a horizontal row in Tkinter. I do this by looping over a list, and loading the corresponding images from the working directory.
I place the images according to the index multiplied with a certain amount of spacing. However, when i actually place the images, they all get placed on top of each other in the last spot, instead of spaced out. The count value works fine, and when i print(spacing*(count+1)) it outputs the correct values but when placing they all get bunched up in the last place.
Does this have something to do with the Label() class?
for count, mood in enumerate(mood_options):
mood_img = Image.open(f"img/{mood}.png")
mood_img_copy = mood_img.resize(img_size, Image.ANTIALIAS)
mood_img_resized = ImageTk.PhotoImage(mood_img_copy)
mood_img_label = Label(root, image=mood_img_resized).place(relx=spacing*(count+1), rely=0.35)
print(spacing * (count + 1))
EDIT: I have used this exact method for placing buttons, see below:
for count, mood in enumerate(mood_options):
mood_btn = Button(root, text=mood.capitalize(), command=lambda mood=mood: register_mood(mood), width=7) \
.place(relx=(count + 1) * spacing, rely=0.5)
This works flawlessly, which makes me wonder why it wouldn't work with images, instead of buttons.

If the same logic works for buttons, then the problem might be the image is garbage collected, in this case you cannot store the image as an attribute of some class to hold reference, because over each iteration each image will be overwritten, holding refence to the last image only. Same happens with global as well. So the way to go here would be appending to a list. Try something like:
lst = []
for count, mood in enumerate(mood_options):
mood_img = Image.open(f"img/{mood}.png")
mood_img_copy = mood_img.resize(img_size, Image.ANTIALIAS)
mood_img_resized = ImageTk.PhotoImage(mood_img_copy)
lst.append(mood_img_resized)
Label(root, image=mood_img_resized).place(relx=spacing*(count+1), rely=0.35)
print(spacing * (count + 1))
Though it would be much better to place stuff using grid to place it in a grid like manner. If your worried about responsiveness of the window then look at weight:
from tkinter import *
root = Tk()
mood_options = ['a', 'b', 'c']
for count, mood in enumerate(mood_options):
Label(root, text=mood).grid(row=0,column=count,padx=50)
root.grid_columnconfigure(count,weight=1)
root.grid_rowconfigure(0,weight=1)
root.mainloop()

Is your spacing the actual amount of space in pixels?
If so, leave away the relx and only use x. relx has to be a float between 0.0 and 1.0.

Related

Position / lot size based on buy entry and stop gap

I'm trying to code in Python my lot size based on a positive order signal.
Below is the expected output which was done in excel.
The logic is:
Lot_size = IF (Order_Signal=1, then Prior_Period_Portfolio_Value * Risk_pct / Stop_gap,
elif(Active=0, 0, prior period lot size)) risk_pct=0.02
I'm having a having a hard time to reproduce this in excel, specifically the last component where it refers to the prior period lot size.
It depends on how you store these data in Python. But for simplicity I'll assume each variable is in its own list.
order_signal = [0,0,...-1,0]
stop_gap = [0.44,1.13,...1.94,9.06]
prior_period_portfolio_value = [10000,10000,...9900,9807.5]
active = [0,0,...1,0]
lot_size = [0] * len(order_signal)
risk_pct = 0.02
for i = 1:len(order_signal):
if order_signal[i] == 1:
lot_size[i] = prior_period_portfolio_value[i] * risk_pct / stop_gap[i]
elif active[i] == 0:
lot_size[i] = 0
else:
# just need to be sure this doesn't happen on the first iteration
lost_size[i] = lot_size[i-1]
What I learn it from basic app developing courses (PhP) I was use itand on game dev fro sorting data in tables. So the trick here will be to create first the columns and then to add rows as childrens.
On tkinter I will do it like that:
1 - I will create a frame extended vertical as parent
frame = Frame()
frame.pack(expand=True, fill="y", side="left")
2 - I will add entrys extended horizontal as childrens
entry = Entry(frame)
entry.pack(expand=True, fill="x", side="top")
In this case all childrens will have same width.
If you want to use labels just for showing data for every child I will make a frame (same like entry example) and inside of that I will add label (same like entry but with side="right") and all text will have same width, and will be aligned on right.

Changing the text of "mass-produced" labels

Hy All,
I'm creating a layout for a database, and made a big canvas which are the lines, spawning smaller canvas inside them (as cells) to contain labels for the data. It looks nice, but the problem is, that due to this "mass-creation" of canvas and label widgets, none of them stays uniqly addressable, they are all named after the same variable when created in a for loop. Any idea how to tag/address them during the creation so I can edit them later?
for f in range(15)
z = z+1
f = Label(someFrame, width = 45 if z < 4 else 12, text = f, borderwidth=2, relief="groove", bg = "#E5E5E5" if Color == True else "#B2B2B2" )
f.pack(side = LEFT)
It may look a bit messy, but you have a picture at least how the widgets are being created and what is my issue.
You can store your widgets in a dictionary. Something like this:
widget_dict = {}
for idx in range(10):
widget_dict['abc' + str(idx)] = label(root, ...)
Then you can access each widget through its dictionary key:
widget_dict[abc2].config(text='Banana')
Before your for loop create a list. Then inside of the for loop just append every label to the list. Or you can use a dictionary to store them, depending on how you want to deal with that.

How to move images using grid?

I'm using this code to display images + text to the screen:
root = Tk()
for i in range(5):
img = some_function_that_returns_ImageTk_PhotoImage()
ls.append(img)
panel = Label(root, image = img)
txt = Label(root, text = str(1+i))
panel.grid(row = 1, column = i)
txt.grid(row = 1, column = i)
root.mainloop()
and I get these 5 images + text lines displayed, but what I want is to have some space between each image.
So, I tried changing the column value to 2*i but that didn't
help. If I changed only the column value in panel, it lined up
one image and then one text and so on, until 5 < 2*i and then it
went back to lining the images one after the other - not what I
expected
Then, I tried changing the column value to 2*i for both label & txt. Didn't work either. It actually gave the same results as just using i. What am I missing here?
you will need to use padding when setting the grid:
panel.grid(row = 1, column = i,padding=(5,5,5,5))
you use it as a tuple containing the amount of pixel padding you want for your widget in each direction, i usually set them the same as above, but you can play around and see what works

Resizing tkinter listbox to width of largest item, using .grid

I have two listboxes that are side by side. They use the lstBox.grid() method to order them in the window. I then have a dropdown option that changes the items displayed in one of the listboxes. The ultimate aim here is to be able to "add" items from one box to the other, and remove ones from the other. My issue is that I don't know how to expand the list box width to be that of the largest item it contains. I have a method that is used for handling when the dropdown is changed, and determining its value to change the items as appropriate, but te listbox doesn't change width.
I am aware that by using lstBox.pack(fill=X,expand=YES), the listbox will resize, but i'm using the .grid() geometry.
Any suggestions?
You can list all your items to find the biggest (if there aren't too much it should be fine). For instance with strings you count their length with 'len(item)'.
Then, when you create your listbox (not when you grid it) your set its width with 'width = "The size you want" ', if the size you put in there is well defined with regard to the length of the biggest item, you shouldn't have any problem.(I think I remember, the listbox's width's unity is given by the size of the text in it, but it needs to be checked)
I don't know grid that much, so that I don't know if there is any faster option to do it.
It should look something like this:
len_max = 0
list_items = ["item2", "item2", "item3+a few characters for the size"]
for m in list_items:
if len(m) > len_max:
len_max = len(m)
import tkinter
master = Tk()
my_listbox1 = Listbox(master, width = len_max)
my_listbox1.grid(row = 0, column = 0)
my_listbox2 = Listbox(master, width = len_max)
my_listbox2.grid(row = 0, column = 1)
my_listbox1.insert(END, list_items[0])
my_listbox2.insert(END, list_items[1])
my_listbox2.insert(END, list_items[2])
master.mainloop()

Python 'grid()' ignores row/column/sticky options

I'm trying to make a lil' card game. It's one player, against a CPU, and it's just as simple as that. A game. However, games aren't fun if they aren't played by the rules, and in this case, the .grid() doesn't want to play by it's rules (.grid(row, column, sticky). The code executes fine, console reports no error, and it compiles, executes, and "works" completely. However, the image label doesn't move at all.
NOTE: I'm not sure if it's because of the method that I use to display images, if it doesn't work with images, or it's just plain bugged.
Here's the code, as well as the output.
Python
crdImg = []
usrStk = None
cpuStk = None
i = 1
#define cards
while i < 57:
i = i + 1
crdImg.append('img/cards/%s.png' % (i - 1))
usrStk = crdImg[54]
cpuStk = crdImg[55]
#define card images
usrCrdImg = Image.open(usrStk)
usrCrdBg = ImageTk.PhotoImage(usrCrdImg)
usrCrd = tkinter.Label(self, text="", image=usrCrdBg, borderwidth=1)
usrCrd.grid(row=4, column=4)
usrCrd.image = usrCrdBg
usrCrd.pack()
Output
It seems you are first positioning the label with grid, but then overriding that position with pack. Do not use grid and pack layout managers together!
Remove the line usrCrd.pack() and change CardGame(root).pack() to CardGame(root).grid(), then it should work.
Note, however, that unless you put something into the other rows and columns, usrCrd.grid(row=4, column=4) will still put the card in the top-left corner, as the other rows and columns have zero width and height.

Categories

Resources