tkinter gui glitching out
anyone know why my tkinter is glitching out like this after around 2.5 minutes?
this code is the minimum example so it wont have the coloured cells but it is the same problem
from tkinter import *
import random
tk = Tk()
tk.wm_title("Battleship")
# forming tkinter window
def baseGrid():
tk.player_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
tk.ai_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
tk.player_canvas.grid(row=1, column=0, padx=50)
tk.ai_canvas.grid(row=1, column=1, padx=50)
for x in range(10):
for y in range(10):
tk.player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
tk.ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
while True:
tk.update()
tk.update_idletasks()
place = baseGrid()
Your loop was causing a memory leak. I'm not sure exactly because I didn't test what was causing it, but I'm almost positive it was because you were drawing an infinite amount of rectangles on top of each other. I simply just changed your code to how I would write it to fix it.
from tkinter import *
import random
tk = Tk()
tk.wm_title("Battleship")
# forming tkinter window
# While technically you can add the canvas objects to your window I don't know if that is best practice.
player_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
ai_canvas = Canvas(tk, height=300, width=300, highlightbackground='black', highlightthickness=0.5)
def baseGrid():
player_canvas.grid(row=1, column=0, padx=50)
ai_canvas.grid(row=1, column=1, padx=50)
for x in range(10):
for y in range(10):
player_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
ai_canvas.create_rectangle(x * 30, y * 30, 300, 300, fill='white')
baseGrid() # you are not returning anything so you do not need the place variable
tk.mainloop() # you should just run mainloop so that Tkinter can manage the loop.
Related
I'm trying to open a Turtle window from a GUI to select a position on the image with a mouse click. The x and y coordinates are then returned as an input to the GUI.
Here is a minimal working example:
from tkinter import *
from tkinter import font as tkFont
import turtle
xclick = 0
yclick = 0
def callback3():
getcoordinates()
def getcoordinates():
screen = turtle.Screen()
screen.setup(400, 400)
screen.bgpic("stunden.gif")
screen.onscreenclick(modifyglobalvariables)
def modifyglobalvariables(rawx,rawy):
global xclick
global yclick
xclick = int(rawx//1)
yclick = int(rawy//1)
print(xclick)
print(yclick)
turtle.bye()
root = Tk()
helv30 = tkFont.Font(family='Helvetica', size=30)
button1 = Button(root, text = "1", width=3, font=helv30, borderwidth=0, command=callback3)
button1.grid(row=0, column=0, padx=5, pady=0)
root.mainloop()
Then the error image "pyimage2" doesn't exist shows up. I found out, that it has something to do with two instances of Tk, as there is the root and the turtle window and that I should solve it with Toplevel(). However, after hours of research and try and error I still could not come up with the right solution to make my code work. Any help is greatly appreciated.
Here's how to implement it directly in tkinter — so no turtle module required — as I suggested earlier in a (now-deleted) comment:
from tkinter import *
from tkinter import font as tkFont
CLOCK_IMAGE_PATH = 'clock.png'
xclick, yclick = 0, 0
def callback3():
window = Toplevel()
window.title("Stunden")
img = PhotoImage(file=CLOCK_IMAGE_PATH)
img_width, img_height = img.width(), img.height()
window.minsize(width=img_width, height=img_height)
canvas = Canvas(window, width=img_width, height=img_height)
canvas.pack()
canvas.image = img # Keep reference to avoid image being garbage collected.
canvas.create_image(0, 0, anchor='nw', image=img)
canvas.bind("<Button-1>", get_coordinates) # Set up event-handler callback.
def get_coordinates(event):
global xclick, yclick
xclick = int(event.x // 1)
yclick = int(event.y // 1)
print(f'xclick={xclick}, yclick={yclick}')
root = Tk()
helv30 = tkFont.Font(family='Helvetica', size=30)
button1 = Button(root, text="1", width=3, font=helv30, borderwidth=0, command=callback3)
button1.grid(row=0, column=0, padx=5, pady=0)
root.mainloop()
So I want it to keep moving with the assigned speed, but it just moves once and it stops.
I thought the after function would help but it doesnt..
Also I want to know what the number does inside the after brackets
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width=1000, height=1000, background='black')
canvas.pack()
circle = canvas.create_oval(0, 0, 10, 10, fill='white')
def move():
canvas.move(circle, 100, 100)
move()
canvas.after(40, move())
root.mainloop()
You have to pass only function name in after() as below...
canvas.after(40, move)
Instead of...
canvas.after(40, move())
Mean after 40 milliseconds after() function will be call and then your object will be move.
You need to call after(...) inside move():
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width=1000, height=1000, background='black')
canvas.pack()
circle = canvas.create_oval(0, 0, 10, 10, fill='white')
def move():
canvas.move(circle, 10, 10)
canvas.after(50, move)
move()
root.mainloop()
Refer here on how to use after() function.
I was experimenting with tkinter and was using the following code as a tester:
import keyboard
from time import sleep
from tkinter import *
tk = Tk()
canvas = Canvas(tk, width=400, height=400)
canvas.pack()
a = 0
if keyboard.is_pressed('q'):
a = 1
if a == 1:
canvas.create_line(0,0,400,400)
tk.mainloop()
No canvas appears when I run this code. I have tried using a debug message instead of creating a line, as well as shifting "tk.mainloop" but the canvas does not show up. However, when I do not use a while loop but a for loop the canvas appears. The program that I plan on making needs an infinite loop. Is there a way to do this in a way that works with tkinter?
Thanks in advance and my apologies for a question that is probably down to some simple error of mine.
Tkinter has bind() to assign function to key/mouse/event so you don't need keyboard module and while loop.
import tkinter as tk
def myfunction(event):
canvas.create_line(0, 0, 400, 400)
root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=400)
canvas.pack()
root.bind('q', myfunction)
root.mainloop()
EDIT: something more funny - every q create random line
import tkinter as tk
import random
def myfunction(event):
x = random.randint(0, 400)
y = random.randint(0, 400)
canvas.create_line(x, y, 400, 400)
root = tk.Tk()
canvas = tk.Canvas(root, width=400, height=400)
canvas.pack()
root.bind('q', myfunction)
root.mainloop()
Or like Picasso
import tkinter as tk
import random
def myfunction(event):
x1 = random.randint(0, 400)
y1 = random.randint(0, 400)
x2 = random.randint(0, 400)
y2 = random.randint(0, 400)
canvas.create_line(x1, y1, x2, y2)
root = tk.Tk()
root.title('Picasso')
canvas = tk.Canvas(root, width=400, height=400)
canvas.pack()
root.bind('q', myfunction)
root.mainloop()
I've been trying to make a function run when I click a rectangle on a tk canvas.
Here is the code:
from tkinter import *
window = Tk()
c = Canvas(window, width=300, height=300)
def clear():
canvas.delete(ALL)
playbutton = c.create_rectangle(75, 25, 225, 75, fill="red")
playtext = c.create_text(150, 50, text="Play", font=("Papyrus", 26), fill='blue')
c.pack()
window.mainloop()
does anyone know what I should do?
You can add tags on the items you want to bind events to.
The event you want here is <Button-1>, which is left mousebutton.
To apply this to your example, you can do like this:
from tkinter import Tk, Canvas
window = Tk()
c = Canvas(window, width=300, height=300)
def clear():
canvas.delete(ALL)
def clicked(*args):
print("You clicked play!")
playbutton = c.create_rectangle(75, 25, 225, 75, fill="red",tags="playbutton")
playtext = c.create_text(150, 50, text="Play", font=("Papyrus", 26), fill='blue',tags="playbutton")
c.tag_bind("playbutton","<Button-1>",clicked)
c.pack()
window.mainloop()
I was trying to create a simple moving block using tkinter in Python 3, and everything was working until I imported time. The window now won't open. I've tried removing the import, and it doesn't help. This is my code:
from tkinter import *
import time
canvas_height = 400
canvas_width = 600
canvas_colour = "grey50"
moveBoolean = "True"
def move():
global moveBoolean
while moveBoolean == "True":
time.sleep(0.005)
canvas.move(square, 90, 90)
time.sleep(0.005)
canvas.move(square, 180, 180)
time.sleep(0.005)
canvas.move(square, 50, 100)
window = Tk()
canvas = Canvas(bg=canvas_colour, height=canvas_height, width=canvas_width, highlightthickness=0)
canvas.pack()
square = canvas.create_rectangle(50, 50, 50, 50, width=50, fill="black")
move()
window.mainloop()
These problems are generally solved with the use of classes, which you should learn and use before coding GUIs IMHO. You should not use time() as it can interrupt the infinite Tkinter loop. Use Tkinter's after() instead. Also, you never set moveBoolean to False, so the while statement runs until the program is cancelled, and the second time through the square will be off the canvas, which is why you don't get anything visible. The following solves your problems but again would be better if a class structure were used.
from tkinter import *
from functools import partial
canvas_height = 400
canvas_width = 600
canvas_colour = "grey50"
moveBoolean = "True"
def move_it(ctr=0):
if ctr < len(coords):
x, y = coords[ctr]
ctr += 1
print ctr, x, y
canvas.move(square, x, y)
window.after(1000, partial(move_it, ctr))
window = Tk()
canvas = Canvas(bg=canvas_colour, height=canvas_height,
width=canvas_width, highlightthickness=0)
canvas.pack()
square = canvas.create_rectangle(50, 50, 50, 50, width=50, fill="black")
coords = ((90, 90),
(180, 180),
(50, 50))
move_it()
window.mainloop()