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()
Related
im still learning to use Python and Tkinter.
I have created a bit of code which (i thought) should create a canvas with 2 dots on and afterwards continuously printers the position of the mouse curser
from tkinter import *
from win32 import win32gui
win = Tk()
def mouse_pos():
flags, hcursor, (x, y) = win32gui.GetCursorInfo()
return {"x": x, "y": y}
win.geometry("1500x900")
win.configure(background="black")
g_circle = Canvas(win, width=100, height=100, bg="black", bd=1, highlightthickness=0)
g_circle.place(x=100, y=100, in_=win)
g_circle.create_oval(50, 50, 100, 100, fill="green", offset="200,200", outline="white")
b_circle = Canvas(win, width=100, height=100, bg="black", bd=1, highlightthickness=0)
b_circle.place(x=1300, y=700, in_=win)
b_circle.create_oval(50, 50, 100, 100, fill="blue", outline="white")
while True:
print(mouse_pos())
win.mainloop()
I know there is an infinite loop but i am just testing it for now.
This issue is that when i run this code a TK window opens of the canvas with 2 circles and then a cmd displays an single value for x and y coordinate in text. The coordinates do not continue to update unless i close the TK window and i dont know why.
Ill post a screenshot in hopes it helps.
Any help is appreciated.
win.mainloop() will block the while loop until the main window is closed.
You can use .after() to replace the while loop:
...
def mouse_pos():
# no need to use external module to get the mouse position
#flags, hcursor, (x, y) = win32gui.GetCursorInfo()
x, y = win.winfo_pointerxy()
print({"x": x, "y": y})
# run mouse_pos() again 10 microseconds later
win.after(10, mouse_pos)
...
''' don't need the while loop
while True:
print(mouse_pos())
win.mainloop()
'''
# start the "after loop"
mouse_pos()
win.mainloop()
I'm trying to make a basic game in Tkinter that involves pressing a start button and making a shape appear which is working, then when you click on the shape it gets deleted and moved to a different random location.
I am getting NameError: name 'square' is not defined when I try to run it.
root=Tk()
frame=Frame(root)
can = Canvas(root, width=400, height=400)
can.pack(side=TOP)
def makeShape():
xpos = random.randint(1, 400)
ypos = random.randint(1, 400)
square=can.create_polygon(xpos, ypos, xpos + 40, ypos, xpos + 40, ypos + 40,
xpos, ypos + 40, fill="blue")
can.tag_bind(square,"<Button-1>",deleteShape)
def deleteShape(event):
can.delete(square)
but1 = Button(frame, text="Start", command=makeShape)
but1.grid(row=1, column=2)
frame.pack(side=BOTTOM)
root.mainloop()
It is because square is a local variable inside makeShape(), so it cannot be accessed outside the function.
You can use tags option in create_polygon() instead. If you want to move the square when it is clicked, deleteShape() is not necessary at all. Just using makeShape() is enough:
from tkinter import *
import random
root=Tk()
frame=Frame(root)
can = Canvas(root, width=400, height=400)
can.pack(side=TOP)
def makeShape():
# delete existing square
can.delete("square")
# create square at random position
xpos = random.randint(1, 360)
ypos = random.randint(1, 360)
can.create_polygon(xpos, ypos, xpos+40, ypos, xpos+40, ypos+40, xpos, ypos+40,
fill="blue", tags="square")
# call makeShape() when the square is clicked
can.tag_bind("square", "<Button-1>", lambda e: makeShape())
but1 = Button(frame, text="Start", command=makeShape)
but1.grid(row=1, column=2)
frame.pack(side=BOTTOM)
root.mainloop()
While it's not good practice, if you add line global square to makeShape() it will run as expected.
That's because if the name is assigned first time inside a block, it won't be visible to parent or sibling blocks.
There are alternatives, considered better for readability and more practical, but my suggestion is the quickest fix to your problem.
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.
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()