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.
Related
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.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
Hello fellow progammers. I am new to programming and I am looking for some help on a project creating an American flag through tkinter. This is really my first practice with it. My problem is actually creating the recurring stripes. My idea was to through my .pack() in a loop and let the program pack each stripe one after another (red then white). I use i % 2 == 0 to tell if i is even or odd. If i is even, then pack a red stripe in. If not, then a white stripe. When I run the code below, I only see one red stripe in a sea of white. Please show me the error of my ways.
My idea is to create the stripes then layer the sea of blue over the stripes, and then somehow fill the blue with '*' for stars. Bonus points if you could also point me in a good direction to that end as well.
Thank you for your time.
from tkinter import *
window = Tk()
window.geometry("500x300")
red_stripe = Label(window, bg= "red")
white_stripe = Label(window, bg= "white")
# sea_of_blue = Frame(window, bg= "blue", width= 220, height= 130)
for i in range(5):
if i % 2 == 0:
one.pack(fill=x)
else:
two.pack(fill=x)
# sea_of_blue.place(relx= 0)
window.mainloop()
Example 1:
I declared the label inside the loop as follows, and it seems to work:
from tkinter import *
window = Tk()
window.geometry("500x300")
for i in range(10):
if i % 2 == 0:
Label(window, bg= "red",width=500).grid(row=i)
else:
Label(window, bg= "white",width=500).grid(row=i)
window.mainloop()
Notice that I'm defining the label inside the loop, so that new label gets created each time and gets placed at alternate position, while range(10), limits it to 10 strips. Here I'm giving width=100 just so that the label fills the whole window up.
Example 2:
If your not planning to re-use the label, Example 1 is fine, else if you want to make some other use of it, then you have to assign a variable and grid() separately, like:
for i in range(5):
if i % 2 == 0:
first = Label(window, bg="red",width=500)
first.grid(row=i)
else:
second = Label(window, bg="white",width=500)
second.grid(row=i)
But this gives you control over the last respective labels only.
Example 3:
Or again, if you want individual control over the strips, then create a label and append it to a list and call the nth item of the list to get the nth label.
labels = []
for i in range(5):
if i % 2 == 0:
labels.append(Label(window, bg= "red",width=100))
labels[i].grid(row=i)
else:
labels.append(Label(window, bg= "white",width=100))
labels[i].grid(row=i)
Button(window,text='Click me',command=lambda:labels[3].config(bg='green')).grid(row=i+1,sticky='w')
Notice that when you click on the button the 4th label changes color, that is the 4th item in your list. So you can access each label like labels[n] where n is the row number of the required label starting from 0.
Example 4:
A very simplified and better example using ternary operator so as to get rid of the if statements:
labels = []
for i in range(5):
bg = 'white' if i%2 else 'red'
labels.append(Label(window, bg=bg,width=100))
labels[i].grid(row=i)
Your second question however remains unclear and it is also better to just ask one question in one post.
I'm building a little Accountant tool so I stop spending money on useless stuff.
Since I am working with big Lists of Invoices I wanted to structure and color them by Categories, because I need to know where to cut Spending in general.
Since Listboxes don't support Multiline Text and no colors I wanted to use Buttons which dynamically change when scrolling.
I discovered that Buttons don't support fonts which makes working with long IBAN Strings very shitty.
Then I decided to use Label widgets which provide Coloring, Font and Multiline and created my own Widget.
This is the function which gets called when the user is scrolling and the Labels have to change Color and Text:
def Refresh (self):
for button in self.buttons:
try:
index = self.buttons.index(button) + self.ListIndex
if type(self.textList[index]) is list:
button.configure(text = self.textList[index][0] , bg = self.textList[index][1])
else:
button.config(text = self.textList[index])
except IndexError:
button.config(text = " ",bg = "#d9d9d9")
Variable Samples:
self.buttons = A list of Label references created when the Widget gets called length depends on how many buttons the user wants being displayed
self.ListIndex = Basically an Index offset, which gets in/decremented when the user is scrolling up or down
self.textList = list of config data for the Labels which elements maybe string or list
self.textList = [['foo', '#eb3434'],'bar']
index = 0
self.textList[index][0] = Invoice Details to be displayed
self.textList[index][1] = Invoice Group Color for easy recognition
now with only the text config:
button.configure(text = self.textList[index][0])
Expected Result:
Now this is very weird when I try to config the color with:
button.configure(text = self.textList[index][0] , bg = self.textList[index][1])
Not expected Result:
After Scrolling:
After a little bit of semantic debug I found out that the colors are in the correct position. Where text and color appears, to be random.
It seems that I explained my problem very terribly, but I have a problem with the grid function on my label. The label does show up but, I cant change the row/column of it or do any function inside of the brackets.
I put the code of how to replicate the problem there. Putting anything inside of the .grid() brackets does nothing as stated earlier
from tkinter import *
root = Tk()
#To actually see that it does not work
root.geometry("800x600")
Var = StringVar()
Label = Label(root, textvariable=Var)
#Location of problem, adding stuff into the brackets does not change anything. For example: sticky = "ne"
Label.grid()
Var.set("Ha")
root.mainloop()
To get the label to show up on the right side, you can specify the number of columns in the grid and then place the label in the last column. For example, try adding this just after your "#Location of problem" comment:
cols = 0
while cols < 4:
root.columnconfigure(cols, weight=1)
cols += 1
Label.grid(column=3)
Please allow me to explain the problem I am facing. I am a undergraduate student who started learning Python a couple of month ago. So, I am new and please bear with me if the experts found them rather naive.
The intention was very simple. I want to place 5 menu buttons in parallel (say in one row, well, this is not the pressing issue though) in a tkinter parent frame. What I did was to introduce 5 sub-frames and place the menu button on them one by one. The idea to use sub-frame was to make space for centering and better layout. Using the most straight-forward fashion, I did it one by one: Define a sub-frame and place a menu button. It all worked well.
Now I am trying to avoid the repeated codes and to lay out the menu buttons and sub-frames using for loops, since the sub-frames and buttons are technically identical except the gird locations and labels are different. I came up with the following code.
Python compiler didn't report any errors. But, only the last button ("Other") was displayed while other buttons are missing. I am having difficulty sorting out what exactly went wrong.
indBtnFrame = [tkinter.Frame(self.parent)] * 5
for i in range(len(indBtnFrame)):
column_index = (i+1)*2
indBtnFrame[i].grid(column=column_index,
row=0,
columnspan=2,
rowspan=1,
sticky="WENS")
for r in range(1): # 1 row in total.
indBtnFrame[i].rowconfigure(r, weight=1)
for c in range(1): # 1 column in total.
indBtnFrame[i].columnconfigure(c, weight=1)
# To fix the grid size.
indBtnFrame[i].grid_propagate(False)
indBtnLabel = ["Street",
"City",
"Postcode",
"Province",
"Other"]
indBtn = []
for i in range(len(indBtnLabel)):
button_label = tkinter.StringVar()
button_label.set(str(indBtnLabel[i]))
temp_widget = tkinter.Menubutton(indBtnFrame[i],
textvariable=button_label,
relief=tkinter.GROOVE)
indBtn.append(temp_widget)
for i in range(len(indBtn)):
indBtn[i].grid(column=0, row=0,
columnspan=1, rowspan=1,
sticky="WENS")
indBtn[i].menu = tkinter.Menu(indBtn[i], tearoff=0)
indBtn[i]["menu"] = indBtn[i].menu