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()
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()
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.
Could anyone share with me how to print the text of the text widget added to a Canvas object? In the code below, I want the system return the value of "hello" when mouse on the text, however, it turns out giving me "1". Don't know why. Could anyone help me?
Many many thanks!!!
import tkinter
from tkinter import *
def show_text(event):
print (canvas.text)
master = tkinter.Tk()
canvas = tkinter.Canvas(master, width = 200, height = 100)
canvas.pack()
canvas.bind('<Enter>',show_text)
canvas.text = canvas.create_text(20, 30, text="hello")
mainloop()
According to the canvas docs:
You can display one or more lines of text on a canvas C by creating a
text object:
id = C.create_text(x, y, option, ...)
This returns the object ID of the text object on canvas C.
Now, you gotta modify the code something like this:
import tkinter
from tkinter import *
def show_text(event):
print (canvas.itemcget(obj_id, 'text'))
master = tkinter.Tk()
canvas = tkinter.Canvas(master, width = 200, height = 100)
canvas.pack()
canvas.bind('<Enter>',show_text)
obj_id = canvas.create_text(20, 30, text="hello")
mainloop()
Follow up (see the documentation for Label.config:
import tkinter
from tkinter import *
from tkinter import ttk
def show_text(event):
print (canvas.itemcget(canvas.text, 'text'))
#The command of writing text 'hello' in sch_Label to replace the text 'the info shows here'
sch_Label.config(text = 'hello!')
master = tkinter.Tk()
canvas = tkinter.Canvas(master, width = 200, height = 100)
canvas.pack()
canvas.bind('<Enter>',show_text)
canvas.text = canvas.create_text(20, 30, text="hello")
pad1 = ttk.Notebook(master)
pad1.pack(side=RIGHT, expand=1, fill="both")
tab1 = Frame(pad1)
pad1.add(tab1, text = "Schedule")
pad1.pack(side=RIGHT)
sch_Label = ttk.Label(tab1, text='The info shows here')
sch_Label.pack(side="top", anchor="w")
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()
I'm writing 3 functions in Tkinter. Each function is in the form ObjectName(c,x,y) where c is the name of the canvas. I want each function to draw shape in any given canvas.
Example:
from Tkinter import *
root = Tk()
def line(c,x,y):
root = Tk()
c = Canvas(root, width=600, height=800)
c.pack()
c.create_line(x-160,y,x+300,y)
drawLine(c,200,300)
root.mainloop()
Problem:
when I call the same function to draw two shapes on the same canvas it draws on two different canvases :(
Your code looks to be creating a new canvas object each time you call line (or drawLine, as your function name and usage appears to be inconsistent.) You shouldn't create a new root object and Canvas object in your function.
Try something like this:
from Tkinter import *
def drawLine(c, x, y):
c.create_line(x - 160, y, x + 300, y)
root = Tk()
c = Canvas(root, width=600, height=800)
c.pack()
drawLine(c, 200, 300)
drawLine(c, 300, 400)
drawLine(c, 350, 450)
root.mainloop()