How to use multiple objects? [closed] - python

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 4 years ago.
Improve this question
So I'm using tkinter to generate a maze but the thing is that I used blocks for the walls, I'm still a beginner in python so I don't know how I'm supposed to do this, here is the problem :
To have a block I used block = PhotoImage(file ='images/block.ppm')
block0 = Label(root, image=block)
block1 = Label(root, image=block)
...
I used a script to write me like 425 objects and place them at different places with block0.place(x=20, y=20), I knew it was dumb but I had no idea what to do else, it printed me the maze but when I wanted to close with the command root.destroy
I couldn't make it. I guess it's because I did this dumb thing.
So how am I supposed to make this ?
I tried to learn more about classes but it didn't worked too.
Here is my code https://mega.nz/#F!Z7xB2IJK!NSSLM6rRFJDE5kpMPs6W_Q
Thanks in advance

It took me quite some time to figure out what you want to do. If you haven't found a solution to your problem yet, here is some code to try out.
The first thing you should do is declare a global variable to store all maze blocks.
blocks = [] # create a list for the maze blocks
Then we will need to functions for building and destroying the maze. You already have a similar structure in your code example (destroythemhehe and mazebuilder) but we can greatly improve readability and performance here.
def gamephase():
global menu, quit, block
menu = Button(root, text='Menu', relief=RIDGE, bg='#C90', command=menuevent)
menu.place(x=50, y=540)
quit = Button(root, text='Quitter', relief=RIDGE, bg='#C90', command=destroy_maze)
quit.place(x=670, y=540)
generate = Button(root, text='Generer', relief=RIDGE, bg='#C90', command=build_maze)
generate.place(x=360, y=540)
The function for building the maze is not really complicated:
def build_maze():
global blocks
for x in range(17):
for y in range(25):
if zone[x][y]:
b = Label(root, image=block)
b.place(x=20 + y * 30, y=20 + x * 30) # a formula which calculates the position of the block
blocks.append(b) # add the block to the list
It does basically the same thing as your function mazebuilder but it saves all the Labels to the blocks list which is much cleaner than your blocker function. Now we need a function to destroy the blocks:
def destroy_maze():
global blocks
for x in blocks: # destroy each block
x.destroy()
blocks = []
And we are done! This should work as expected but I haven't tested it thoroughly.
You can make your code even prettier if you use classes instead of global variables. This can also help you prevent some nasty bugs.

Related

Tkinter Label doesn't work as I thought it does [duplicate]

This question already has an answer here:
When should I use root.update() in tkInter for python
(1 answer)
Closed 1 year ago.
Beginner programmer here currently trying to learn Tkinter for a school assignment.
I have a GUI class that stores the Tkinter labels etc, the labels are innitiated like this:
# GUI for Player 1
self.player_1_name_field = Label(
self.root,
text="Player 1",
font=GUI_Settings.player_information_font,
anchor=W,
background=GUI_Settings.playerfield_active_color
)
I then create a Game() object that looks like this:
class Game():
def __init__(self):
self.GUI = GUI()
self.GUI.initializeBoard()
self.GUI.root.mainloop()
When I run the code, the labels do get created and are where they are supposed to be, but are completely black. Once I move or resize the window it instantly becomes how I want it to be, it just behaves weird when at the start of the code
The interesting thing is that I also have a Canvas and a List that work perfectly fine, only the Labels are not cooperative
If you need further info, just ask for it!
Thank you!
Edit 1: I have a function called drawWindow() that redraws the chessboard when I re-configure the window. In the init of the GUI class I set self.root.bind("<Configure>", self.drawWindow). If I remove that line of code, the Labels work but the Canvas doesn't anymore. I'm so confused. For anyone wanting to take a look at my tiny code: https://codeshare.io/DZYzyZ
See comment of Thingamabobs
The issue is self.root.update(). Remove this line and you'll be fine.
When should I use root.update() in tkInter for python.
This works but you shouldn't do it
This is a tricky issue. Your problem come from the bind of the configure event. Bind to the root window, it is applied to all sub-widgets of the window, which cause the bug (I don't know why yet).
This will solve your issue (line 202):
self.chessboard.bind("<Configure>", self.drawWindow)
instead of:
self.root.bind("<Configure>", self.drawWindow)
Result without moving or resizing the window:
I found the information here (french forum).

Problem with binding 2 functions to a button in tkinter

First of all this is my code:
button_1 = Button(
image=button_image_1,
borderwidth=0,
highlightthickness=0,
command=lambda:[get_to_main_when_clicked(),delete_red_border()],
relief="flat"
)
As you can see I binded 2 functions to this button. To the first one: If a specific condition is true, then the function lets an image appear. The second one then should wait 3 seconds and should delete the appeared image. The only really weird problem is, that it no matter what I do, first executes the delete_red_border() function. It waits 3 seconds, then its trying to delete an image that couldn't be defined and globalized, because the get_to_main_when_clicked() function wasn't executed. How can I solve this?
PS: The specific condition is true.
Don't do this. Create a function specifically for this button. A function is much easier to understand and debug than a lambda, especially a complex lambda. You can then put any logic you want inside the function.
def do_something():
get_to_main_when_clicked()
delete_red_border()
button_1 = Button(..., command=do_something)
I found the solution for it. The problem was, that it didn't refreshed/updated the window after finishing the first function. That was solved by one line of code:
window.update()

Create a function that ends mainloop and starts new one in tkinter

I'm writing my first GUI program today using Tkinter and I have stumbled onto a problem. I am trying to make a game that starts with an introduction window that closes after you press a button, then opens a new window where you can choose one of two modes. Unfortunately, I just can't get it running. It looks a little something like this.
#These are the functions that I defined to make it work
def start():
root.destroy()
def Rules_mode_1():
root.destroy
rules1 = Tk()
understood1 = Button(rules1, text="I understood", command="Start_game_mode_1")
understood.pack()
rules1.mainloop
# I haven't added rules 2 yet cause I couldn't get it to work with rules 1 so I haven't even #bothered but it would be the same code just switching the 1 for a 2. But really it isn't even
#necessary to have 2 different rule functions because the rules are the same but I couldn't think
#of another way to go about it. if you have an idea let me know
def Start_game_mode_1():
rules1.destroy #<----- THIS IS WHERE THE PROBLEM LIES. JUST DOESN'T RUN
gamemode1 = Tk()
#Here I would have the game
gamemode1.mainloop()
#now same here don't have gamemode 2 yet cause it just doesn't work yet
#This is where it really starts
root = Tk()
startbutton = Button(root, text="Start", command=start)
startbutton.pack
root.mainloop
root = Tk()
def mode():
mode1 = Button(root, command=Rules_mode_1)
mode1.pack
mode2 = #Buttonblablabla
mode()
root.mainloop()
Now I've been trying around for hours, trying to give the mainloops different names. For example giving the
rules1.mainloop
#the name
root.mainloop
but that obviously didn't work. I tried it with dozens of helper function and with the lambda expression and did hours of research but just can't seem to fix it. Does anybody have any ideas? Please be respectful and keep in mind it's my first time using Tkinter.
Thank you for your help!
After the comments didn't really help me I just tried things out for hours and in case anybody ever is having a a similar problem and reads this: The rules1 variable is inside a function, and therefore only local, which means it can't be destroyed in another function. I fixed it by making it a global, like:
def Rules_mode_1():
root.destroy
global rules1
rules1 = Tk()
understood1 = Button(rules1, text="I understood", command="Start_game_mode_1")
understood.pack()
rules1.mainloop
After that I could destroy the mainloop in the next function.

Having trouble updating int label but can update string label fine

I'm sure someone is going to mark this as a duplicate the second I post it, but I assure you, I've been looking for hours. I'm brand new to tkinter so bear with me as I'd like a really straightforward answer if possible. Anything related to this specifically was a bit complex for me right now and I didn't feel it answered my question.
I know how to have a Label update with textvariable and StringVar. However, I'm trying to update an integer and I can't seem to figure it out for some reason. The number updates and prints through the console but I can't figure out the right syntax to get it to show up on the interface. It either just shows 0 (as the default variable shows) or there is no text there at all depending on what I've changed the code to)
So all I'm doing is simply incrementing a number. Let's leave it at that for now. And if anyone has any resources to more straightforward documentation please let me know because it seems tkinter in general is pretty obscure in documentation online as far as I can tell.
my_count = 0
def increase_mycount():
global my_count
increment = int(my_count) + 1
my_count = str(increment)
print(my_count)
Label(root, textvariable=my_count).grid(row=2, column=1)
Button(root, text="+", command=inc_mycount).grid(row=3, column=2)
This is where it's at right now, I've tried changing my_count into an IntVar and also a StringVar and I get an error saying I can't use + with int and intvar or int with stringvar
Is there something really simple I'm missing? I'm struggling finding comprehensive documentation on tkinter. It's easy to find Python information but not this really.. I'm in the process of organizing all the info I'd like into some google docs.
Thank you for any time you give. This seems like it should be a really simple thing to do but I've only worked with engines that update things for me. I'm only use tkinter, a .py file, and cmd for this.
And another note, I can't use .set() for this either it seems, like I could for a string. So I'm just struggling with the syntax unless there is a different method for numbers on labels.
You have to use one of tkinter's variable objects when using textvariable. In this case, IntVar.
import tkinter as tk
root = tk.Tk()
my_count = tk.IntVar()
def increase_mycount():
current = my_count.get()
my_count.set(current+1)
tk.Label(root, textvariable=my_count).grid(row=2, column=1)
tk.Button(root, text="+", command=increase_mycount).grid(row=3, column=2)
root.mainloop()

How do you make a constantly refreshing canvas in Python?

I am currently trying to code a basic smartmirror for my coding II class in high school with Python. One thing I'm trying to do is create a welcome text that updates based on what button you press. I am reading the string for the canvas' text from a .txt document that changes depending what user I select. Is there any way to get this to automatically refresh when I change the document's text?
The code I am using to display the message is:
text2 = Canvas(tk, width=500, height=100)
welcometext = text2.create_text(200, 50, text=string, font=('Helvetica', 20, 'italic'))
text2.pack(side=TOP, anchor=Center)
The basic way to do this is have a loop. And every cycle of the loop you should check for user input and redraw. Make sure you break everything up into functions so your loop is clean. Something like this -
canvas = Canvas(tk, width=500, height=500)
text = ''
while(True) {
getUserInput(text)
draw(canvas, text)
}
You can use python's built in input function to get the user input in your getUserInput function.
As an aside, this is a naive approach, because the loop will wait for user input every time before redrawing. The proper way to do this would be to use threading. You could have a thread to capture user input while your main loop does other things. This can get complicated really fast though, due to data synchronization issues. I'd just stick with the naive approach for now.
Also, the variable text2 is misleading. Always try to name your variables to be exactly what they are. In this case, it's a Canvas object, so call it canvas.

Categories

Resources