Tkinter cannot draw to another window - python

I want to do something that should be rather simple, but I'm struggling to make it work.
Basically I have 2 Tkinter windows (canvas_tk and control_tk).
In canvas_tk I want to show an image and draw a circle on top of it.
In control_tk I have an Entry to input the radius of the circle to be drawn.
In my code the critical line is at the very bottom of the code:
self.panel = tk.Label(canvas_tk, image=image)
If I make the label in the control_tk or if I dont specify the parent, it actually works fine and draws the circles in the control_tk window
However I want the circles to be drawn in the canvas_tk window
self.panel = tk.Label(image=image) # Works
self.panel = tk.Label(control_tk, image=image) # Works
self.panel = tk.Label(canvas_tk, image=image) # Fails
Here's my minimal code:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw
control_tk = tk.Tk()
canvas_tk = tk.Tk()
control_tk.geometry("300x300")
canvas_tk.geometry("900x900")
class Drawing:
def __init__(self):
# Numerical entry with a variable traced with callback to "on_change" function
self.radius_var = tk.IntVar()
self.radius_var.trace_variable("w", self.on_change)
tk.Entry(control_tk, textvariable=self.radius_var).grid()
# Initialize image and panel
self.image = Image.new('RGB', (1000, 1000))
self.panel = None
# mainloop for the two tkinter windows
control_tk.mainloop()
canvas_tk.mainloop()
def on_change(self, *args):
print("Value changed") # to check that function is being called
draw = ImageDraw.Draw(self.image)
draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
50+self.radius_var.get(), 50+self.radius_var.get()),
outline='blue', width=3)
image = ImageTk.PhotoImage(self.image)
if self.panel: # update the image
self.panel.configure(image=image)
self.panel.image = image
else: # if it's the first time initialize the panel
self.panel = tk.Label(canvas_tk, image=image)
self.panel.image = image
self.panel.grid(sticky="w")
Drawing()
And the traceback error basically complains about image not existing
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 508, in get
return self._tk.getint(value)
_tkinter.TclError: expected integer but got ""
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/GIT/142-277-00_pyScuti2/test.py", line 29, in on_change
draw.ellipse((50-self.radius_var.get(), 50-self.radius_var.get(),
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 510, in get
return int(self._tk.getdouble(value))
_tkinter.TclError: expected floating-point number but got ""
Value changed
Value changed
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:/GIT/142-277-00_pyScuti2/test.py", line 38, in on_change
self.panel = tk.Label(canvas_tk, image=image)
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2766, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "C:\Users\lab\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 2299, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage1" doesn't exist

First of all, you should not use multiple Tk() instances. Second, you better not using trace() on tracking input change, use bind('<Return>', ...) to trigger drawing after user enters value and press Enter key. Below is a modified code based on yours:
import tkinter as tk
from PIL import Image, ImageTk, ImageDraw
control_tk = tk.Tk()
control_tk.geometry("300x300+800+600")
canvas_tk = tk.Toplevel() # use Toplevel instead of Tk
canvas_tk.geometry("900x900+10+10")
class Drawing:
def __init__(self):
# Numerical entry with a variable traced with callback to "on_change" function
self.radius_var = tk.IntVar()
entry = tk.Entry(control_tk, textvariable=self.radius_var)
entry.grid()
# binding Enter key on entry to trigger the drawing
entry.bind('<Return>', self.on_change)
# Initialize image and panel
self.image = Image.new('RGB', (1000, 1000))
self.panel = None
# mainloop for the main window
control_tk.mainloop()
def on_change(self, *args):
try:
radius = self.radius_var.get()
except:
print('Invalid number')
return
print("Value changed") # to check that function is being called
draw = ImageDraw.Draw(self.image)
draw.ellipse((50-radius, 50-radius, 50+radius, 50+radius),
outline='blue', width=3)
image = ImageTk.PhotoImage(self.image)
if self.panel:
self.panel.configure(image=image)
else:
self.panel = tk.Label(canvas_tk, image=image)
self.panel.grid(sticky='w')
self.panel.image = image
Drawing()

Related

Button Picture Attribute issues with Tkinter

I'm having weird issues with some iterated buttons that are made inside of a function. I have my button list as a global variable and photos are saved within my main python folder.
When I use the Button image= attribute, the buttons aren't clickable and are kind of greyed out with no picture. When I use the Button text= attribute, the buttons are clickable and the text pops up, but the width and height attributes don't run. I haven't been able to find similar issues/answers here.
from tkinter import *
from tkinter import filedialog as fd
from tkinter.messagebox import showinfo
from PIL import Image, ImageTk
def OnSomeClick():
---Some Code---
if Orientation == 1:
for i in range(len(Ordered_xCoord)):
InitButtonPhoto = '{}.png'.format(i)
ButtonPhoto = PhotoImage(file=InitButtonPhoto)
ImageButtonList.append(Button(action_window, command=Command, bd=3, width=110,
height=85, image=ButtonPhoto))
ImageButtonList[i].grid(row=Ordered_yCoord[i], column=Ordered_xCoord[i])
#this top if statement is what runs with my test; the bottom is my original
else:
for i in range(len(Ordered_xCoord)):
ImageButtonList.append(Button(action_window,
image=PhotoImage(file='{}.png'.format(i)),
command=Command, bd=3, width=85, height=110))
ImageButtonList[i].grid(row=Ordered_yCoord[i], column=Ordered_xCoord[i])
When loading the photo through PhotoImage(Image.open(file)), there is a traceback error. I'm not too sure why my photos are out of scope/garbaged or why the command working is dependent on the photo saving.
Traceback Error with Image.open:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Users/.conda/envs/CoordinateMath/lib/python3.8/tkinter/__init__.py", line 1892, in __call__
return self.func(*args)
File "/Users/PycharmProjects/CoordinateMath/TkinterWindow.py", line 163, in Submit
ButtonPhoto = PhotoImage(file=InitButtonPhoto)
File "/Users/.conda/envs/CoordinateMath/lib/python3.8/tkinter/__init__.py", line 4064, in __init__
Image.__init__(self, 'photo', name, cnf, master, **kw)
File "/Users/.conda/envs/CoordinateMath/lib/python3.8/tkinter/__init__.py", line 4009, in __init__
self.tk.call(('image', 'create', imgtype, name,) + options)
_tkinter.TclError: couldn't open "<PIL.PngImagePlugin.PngImageFile image mode=RGB size=990x765 at 0x11034C310>": no such file or directory
Thank you, Matiiss and BryanOakley! The fix was a combo of the latest comment and putting my changing the formatting of my image list.
def onClick():
global Image_List, Ordered_xCoord, Ordered_yCoord, ImagedButtonList
--some code---
for i in range(len(Ordered_xCoord)):
y = myimage.save('{}.png'.format(i))
z = ImageTk.PhotoImage(Image.open('{}.png'.format(i)))
Image_List.append(z)
---more code----
if PaperOrientation == 1:
for i in range(len(Ordered_xCoord)):
InitButtonPhoto = Image_List[i]
ButtonPhoto = InitButtonPhoto
ImageButtonList.append(Button(action_window, command=Command, bd=3, width=110,
height=85, image=ButtonPhoto))
ImageButtonList[i].grid(row=Ordered_yCoord[i], column=Ordered_xCoord[i])
else:
for i in range(len(Ordered_xCoord)):
InitButtonPhoto = Image_List[i]
ButtonPhoto = InitButtonPhoto
ImageButtonList.append(Button(action_window, command=Command, bd=3, width=85,
height=110, image=ButtonPhoto))
ImageButtonList[i].grid(row=Ordered_yCoord[i], column=Ordered_xCoord[i])
Kind of sloppy on my part, but it works.

Tkinter: return self.func(*args) exception

I'm new to python and can't get a test program functioning. The goal was to keep rotating an image until it reaches the desired angle using tkinter GUI. The program runs fine but after reaching to the desired angle the console shows the following exception.
Traceback (most recent call last):
File "/usr/lib/python3.8/tkinter/__init__.py", line 1883, in __call__
return self.func(*args)
File "/usr/lib/python3.8/tkinter/__init__.py", line 804, in callit
func(*args)
StopIteration
And the code is :
import tkinter as tk
from PIL import ImageTk
from PIL import Image
import time
class SimpleApp(object):
def __init__(self, master, filename, **kwargs):
self.master = master
self.filename = filename
self.canvas = tk.Canvas(master, width=500, height=500)
self.canvas.pack()
self.update = self.draw().__next__
master.after(100, self.update)
def draw(self):
image = Image.open(self.filename)
angle = 0
while (angle<90):
tkimage = ImageTk.PhotoImage(image.rotate(angle))
canvas_obj = self.canvas.create_image(
250, 250, image=tkimage)
self.master.after_idle(self.update)
yield
angle += 5
time.sleep(0.1)
root = tk.Tk()
app = SimpleApp(root, 'cat.jpg')
root.mainloop()
Thanks in advance.
This is happening because when you reach the desired angle, the code doesn't enter your while loop, meaning no yield statement is encountered. Thus when you call self.draw().__next__, there is no next element to retrieve.
If you want to keep the current code, simply adding an else statement with a yield afterwards would solve your error
def draw(self):
image = Image.open(self.filename)
angle = 0
while (angle<90):
tkimage = ImageTk.PhotoImage(image.rotate(angle))
canvas_obj = self.canvas.create_image(
250, 250, image=tkimage)
self.master.after_idle(self.update)
yield
angle += 5
time.sleep(0.1)
else:
yield
However I see no point in using the next and yield statements in the function you've made, and would probably have done something like the below instead
import tkinter as tk
from PIL import ImageTk
from PIL import Image
import time
class SimpleApp(object):
def __init__(self, master, filename, **kwargs):
self.master = master
self.filename = filename
self.canvas = tk.Canvas(master, width=500, height=500)
self.canvas.pack()
self.image = Image.open(self.filename)
self.angle = 0
self.master.after(100, self.draw)
def draw(self):
while self.angle < 90:
tkimage = ImageTk.PhotoImage(self.image.rotate(angle))
canvas_obj = self.canvas.create_image(
250, 250, image=tkimage)
self.angle += 5
self.master.after(100, self.draw)
root = tk.Tk()
app = SimpleApp(root, 'cat.jpg')
root.mainloop()

Insert an JPG image in Python using Tkinter

i'm trying to insert an image using Tkinter but it doesn't work, there is an error message saying : (In fact it is saying that python can't recognise the data in image file)
Traceback (most recent call last):
File "E:/Tle/ISN/Programs (Pyhton)/IMC (Widget) ULTIMATE.py", line 10, in <module>
my_image = PhotoImage(file="C:/Users/mateo.PCMATEO/Pictures/MonCoachPersonnel.jpg")
File "C:\Users\mateo.PCMATEO\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 3545, in __init__
Image.__init__(self, 'photo', name, cnf, master, **kw)
File "C:\Users\mateo.PCMATEO\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 3501, in __init__
self.tk.call(('image', 'create', imgtype, name,) + options)
_tkinter.TclError: couldn't recognize data in image file "C:/Users/mateo.PCMATEO/Pictures/MonCoachPersonnel.jpg"
And here's the code i've entered :
from tkinter import*
import tkinter as tk
window = tk.Tk()
window.title("My Personnal Fitness Coach")
window.geometry("400x500")
window.configure(background='grey')
canvas = Canvas(window, width = 100, height = 100)
canvas.pack
my_image = PhotoImage(file="C:/Users/mateo.PCMATEO/Pictures/MonCoachPersonnel.jpg")
canvas.create_image(0, 0, anchor = NW, image=my_image)
window.mainloop()
The problem is that i don't have any modules except the ones predownloaded with python and i don't want to install some yet. So could you help me?
if you use jpg you must do so
from PIL import ImageTk
then
my_image = ImageTk.PhotoImage(file="MonCoachPersonnel.jpg")
canvas.create_image(50, 50, image=my_image, anchor=NW)
I've simplify the file dir, note that I've increase the dimension of the pic, from 0,0 to 50,50.
Please, try this (only change image file path)
from tkinter import*
import tkinter as tk
from PIL import ImageTk, Image
window = tk.Tk()
window.title("My Personnal Fitness Coach")
window.geometry("400x500")
window.configure(background='grey')
canvas = Canvas(window, width = 100, height = 100)
canvas.pack()
photo_image = ImageTk.PhotoImage(Image.open('xxxx\\racecar.jpg'))
my_image = canvas.create_image(0, 0, image=photo_image, anchor=NW)
# my_image = PhotoImage(file="xxxx\\racecar.jpg")
# canvas.create_image(0, 0, anchor = NW, image=my_image)
window.mainloop()

Putting gif image in tkinter window

I'm trying to insert a gif image in a new tkinter window when a button is clicked but I keep getting this error
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Afro\AppData\Local\Programs\Python\Python35\lib\idlelib\run.py", line 119, in main
seq, request = rpc.request_queue.get(block=True, timeout=0.05)
File "C:\Users\Afro\AppData\Local\Programs\Python\Python35\lib\queue.py", line 172, in get
raise Empty
queue.Empty
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\Afro\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 1549, in __call__
return self.func(*args)
File "C:/Users/Afro/Desktop/mff.py", line 8, in sex
canvas = tkinter.Label(wind,image = photo)
File "C:\Users\Afro\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 2605, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "C:\Users\Afro\AppData\Local\Programs\Python\Python35\lib\tkinter\__init__.py", line 2138, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage1" doesn't exist
Here's the code. The image and the location actually exists.
import tkinter
def six():
wind = tkinter.Tk()
photo = tkinter.PhotoImage(file = 'American-Crime-Story-1.gif')
self = photo
canvas = tkinter.Label(wind,image = photo)
canvas.grid(row = 0, column = 0)
def base():
ssw = tkinter.Tk()
la = tkinter.Button(ssw,text = 'yes',command=six)
la.grid()
base()
What am I doing wrong?
You are trying to create two instances of Tk window. You can't do that. If you want second window or pop-up window you should use Toplevel() widget.
Also, self doesn't mean anything in this context. Using the widget's image property would be better to keep a reference.
import tkinter
ssw = tkinter.Tk()
def six():
toplvl = tkinter.Toplevel() #created Toplevel widger
photo = tkinter.PhotoImage(file = 'American-Crime-Story-1.gif')
lbl = tkinter.Label(toplvl ,image = photo)
lbl.image = photo #keeping a reference in this line
lbl.grid(row=0, column=0)
def base():
la = tkinter.Button(ssw,text = 'yes',command=six)
la.grid(row=0, column=0) #specifying row and column values is much better
base()
ssw.mainloop()

How to draw a polygon on a tkinter canvas using a class?

from tkinter import*
root = Tk()
shape = Canvas(root)
class GUI():
def __init__(self):
pass
def create_polygon(self, points, colour, posit):
try:
shape.delete(self.poly)
except:
pass
self.poly = shape.create_polygon(points, colour, posit)
self.poly.shape.grid(column=posit[0],row=posit[1])
polygon = GUI()
polygon.create_polygon([150,75,225,0,300,75,225,150],'yellow',[1,2])
I'm new to using tkinter and classes but I want to make a very simple class to create a regular polygon. The code in this program should delete any polygon previously made and then proceed to make a new polygon when the program is called but I keep getting an error that I don't understand. Also how would you go about drawing a hexagon instead?
Traceback (most recent call last):
File "//xsvr-02/Students/10SAMP_Al/HW/polygon creator.py", line 19, in <module>
polygon.create_polygon([150,75,225,0,300,75,225,150],'yellow',[1,2])
File "//xsvr-02/Students/10SAMP_Al/HW/polygon creator.py", line 15, in create_polygon
self.poly = shape.create_polygon(points, colour, posit)
File "C:\Python34\lib\tkinter\__init__.py", line 2305, in create_polygon
return self._create('polygon', args, kw)
File "C:\Python34\lib\tkinter\__init__.py", line 2287, in _create
*(args + self._options(cnf, kw))))
_tkinter.TclError: wrong # coordinates: expected an even number, got 11
It's just wrong call parametters.
If you want to change your code, this solution can help you.
Class GUI just inherits from Canvas and doesn't implement anything.
from Tkinter import*
root = Tk()
class GUI(Canvas):
'''inherits Canvas class (all Canvas methodes, attributes will be accessible)
You can add your customized methods here.
'''
def __init__(self,master,*args,**kwargs):
Canvas.__init__(self, master=master, *args, **kwargs)
polygon = GUI(root)
polygon.create_polygon([150,75,225,0,300,75,225,150], outline='gray',
fill='gray', width=2)
polygon.pack()
root.mainloop()
For more help add comments.

Categories

Resources