_tkinter.TclError: image "..." doesn't exist _ ImageGrab.grab() - python

Summary of code purpose: change tk.Button['image'] to either selected file, or screen snip
I'm getting this error:
_tkinter.TclError: image "<PIL.Image.Image image mode=RGB size=600x400 at 0x34045F0>" doesn't exist
But I can't understand why it doesn't exist since if I useprint(self.image_selected) I get
<PIL.Image.Image image mode=RGB size=600x400 at 0x3D16650>
Does it need to be a global variable? Doesn't adding self take care of that?
CODE
import tkinter as tk
from tkinter import filedialog
from PIL import ImageGrab, ImageTk
class MCVE():
def __init__(self, master):
self.master = master
self.ButtonOne = tk.Button(text="start",width=30,height=30,command = lambda: self.GetImg(master))
self.ButtonOne.pack()
self.image_selected = None
def GetImg(self, master):
self.newWin = tk.Toplevel(self.master)
self.ButtonTwo = tk.Button(self.newWin,text="snip", command = lambda: self.Snip(self.master))
self.ButtonThree = tk.Button(self.newWin, text="open", command = lambda: self.FileO(self.master))
self.ButtonTwo.pack()
self.ButtonThree.pack()
def Snip(self, master):
self.image_selected = ImageGrab.grab(bbox=(0,0,600,400))
self.changeImg()
def FileO(self, master):
ret = filedialog.askopenfilename() # filedialog.askopenfilename(initialdir='/home/user/images/')
if ret:
self.image_selected = ImageTk.PhotoImage(file=ret)
self.changeImg()
def changeImg(self):
if self.image_selected:
print(self.image_selected)
#self.ButtonOne['image'] = self.image_selected
self.ButtonOne.config(image=self.image_selected)
def main():
root = tk.Tk()
MCVE(root)
root.mainloop()
if __name__ == '__main__':
main()

I tested the program, and as you stated, the 'snip' button gave me the error. I could fix it by changing the format of the image to a ImageTk.PhotoImage.
def Snip(self, master):
self.image_selected = ImageTk.PhotoImage(ImageGrab.grab(bbox=(0,0,600,400)))
self.changeImg()
I have to say, though, that the photo showed on the button icon after selecting the image was weird, but I guess it was because i tested it with the wrong resolution! ;)

Related

Using a class constructor to handle images tkinter

Hi i'm trying to create a class constructor to handle images in tkinter, since i'll be using many images in my code so I need a way to use images without using so much line of code.
I keep getting the error:
return _modes[mode]
KeyError: 'picture.png'
Here's the code:
from tkinter import *
import tkinter
from random import randint
from PIL import Image
from PIL import ImageTk
root = tkinter.Tk()
root.geometry('700x700')
class PhotoHandler:
def __init__(self,imagepath):
self.imagepath = imagepath
self.image = Image.open(self.imagepath)
self.image = ImageTk.PhotoImage(self.imagepath)
def returnn(self):
return self.image
search = PhotoHandler('picture.png').returnn()
root.mainloop()
You passed a string to the tkinter image. It expects a PIL image or mode. Since you passed a string, it thinks you're using an invalid mode. Pass the image instead:
class PhotoHandler:
def __init__(self,imagepath):
self.imagepath = imagepath
self.image = Image.open(self.imagepath)
self.image = ImageTk.PhotoImage(self.image)
def returnn(self):
return self.image
search = PhotoHandler('picture.png').returnn()
# add label for background image
background_label = tkinter.Label(root, image=search)
background_label.place(x=0, y=0, relwidth=1, relheight=1)
root.mainloop()
Here's the documentation:
https://pillow.readthedocs.io/en/4.2.x/reference/ImageTk.html

Why doesn't my tkinter window show my panel?

I've got the following code:
import tkinter
import cv2
from PIL import Image, ImageTk
import threading
class HudGui:
def __init__(self, window):
# defining everything for video capture and the tkinter window
self.CapDev= cv2.VideoCapture(0)
self.cams = []
self.counter = 0
self.frame = None
self.panel = None
self.wind = window
btn = tkinter.Button(window, text="Snapshot!")
btn.pack(side="bottom", fill="both", expand="yes", padx=10, pady=10)
# defining threading for video stream
self.stopEvent = threading.Event()
self.thread = threading.Thread(target=self.videoLoop(), args=(1,))
self.thread.start()
def videoLoop(self):
while not self.stopEvent.is_set():
# reading and modifying the frame to have the proper data type
self.frame = self.CapDev.read()[1]
image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
image = Image.fromarray(image)
image = ImageTk.PhotoImage(image)
if self.panel is None:
self.panel = tkinter.Label(image=image)
self.panel.image = image
self.panel.pack(side="left") # side="left", padx=10, pady=10
# otherwise, update the panel
else:
self.panel.configure(image=image)
self.panel.image = image
hud = tkinter.Tk()
hud.title("HUD")
HudGui(hud)
hud.mainloop()
When I run this code, nothing happens. I get no window but I do know it is updating the panel (I've tested it with printing messages). Could there be permissions problem for accessing the camera and things like that?
Project info:
Python = 3.7.3
opencv-contrib-python = 3.4.4.19

Class for picture view that change pic on mouse click

I want to make a class that has a picture and it is changed to the next one by mouse click.I'm new to oop, my idea here was to make class similar to real life where there is new class instance for every new picture, is it possible to do it this way? Here is my code
import tkinter as tk
from PIL import Image,ImageTk
class Picture():
_count=1
def __init__(self,window):
self.id=Picture._count
Picture._count+=1
self.img=Image.open(r'C:\ImgArchive\img%s.png' % self.id)
self.pimg = ImageTk.PhotoImage(self.img)
self.lab=tk.Label(window,image=self.pimg)
self.lab.pack()
self.lab.bind('<1>',self.click)
def click(self,event):
self.lab.destroy()
self=self.__init__(window)
window = tk.Tk()
window.title('Album')
window.geometry('1200x900')
pic=Picture(window)
window.mainloop()
It works fine, but i'm not sure that old instances of my class is deleted, are they? And i use self.lab.destroy() because if i dont new picture appears down, like this
instead of this
So why it happens?What is elegant way for it?
Below example produces a simple image viewer tested with path of C:\Users\Public\Pictures\Sample Pictures, let me know if anything's unclear:
import tkinter as tk
from PIL import Image, ImageTk
#required for getting files in a path
import os
class ImageViewer(tk.Label):
def __init__(self, master, path):
super().__init__(master)
self.path = path
self.image_index = 0
self.list_image_files()
self.show_image()
self.bind('<Button-1>', self.show_next_image)
def list_files(self):
(_, _, filenames) = next(os.walk(self.path))
return filenames
def list_image_files(self):
self.image_files = list()
for a_file in self.list_files():
if a_file.lower().endswith(('.jpg', '.png', '.jpeg')):
self.image_files.append(a_file)
def show_image(self):
img = Image.open(self.path + "\\" + self.image_files[self.image_index])
self.img = ImageTk.PhotoImage(img)
self['image'] = self.img
def show_next_image(self, *args):
self.image_index = (self.image_index + 1) % len(self.image_files)
self.show_image()
root = tk.Tk()
mypath = r"C:\Users\Public\Pictures\Sample Pictures"
a = ImageViewer(root, mypath)
a.pack()
root.mainloop()

How to make image pop up on a window Tkinter python3

Hey I'm following a tutorial, https://www.youtube.com/watch?v=a1Y5e-aGPQ4 , and I can't get it to work properly. I'm trying to add an image when you press on a menu button:
from tkinter import *
from PIL import *
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_Window()
def init_Window(self):
self.master.title("GUI")
self.pack(fill =BOTH, expand=1)
#quitButton = Button(self, text = "Quit", command = self.client_exit)
#quitButton.place(x=0,y=0)
menu = Menu(self.master)
self.master.config(menu=menu)
file=Menu(menu)
file.add_command(label='Save',command= self.client_exit)
file.add_command(label='Exit',command= self.client_exit)
menu.add_cascade(label='File',menu=file)
edit = Menu(menu)
edit.add_command(label='Show Image', command=self.showImg)
edit.add_command(label='Show Text', command=self.showTxt)
menu.add_cascade(label='Edit',menu=edit)
def showImg(self):
load = Image.open('Pic.png')
render = ImageTk.PhotoImage(load)
img = Label(self, image=render)
img.image = render
img.place(x=0,y=0)
def showTxt(self):
text = Label(self,text='Hey')
text.pack
def client_exit(self):
exit()
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
I have tried asking around school, StackOverflow, and YouTube for about 3 days now, and nothing has solved my problem, if you need any more info about it please ask. I am getting the error code:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.5/tkinter/__init__.py", line 1558, in __call__
return self.func(*args)
File "/root/Desktop/Python Programs/Tkinter.py", line 35, in showImg
load = Image.open('pic.png')
AttributeError: type object 'Image' has no attribute 'open'
You use import * so you don't know if you use tkinter.Image or PIL.Image . And this is why you shouldn't use import *
Try
from PIL import Image, ImageTk
Images are a bit tricky to get right, some tips: Keep the image object global, to avoid garbage collection, avoid Attribute Error (by reading the docs).
In this example I don t use PIL and I load a gif image
#!/usr/bin/python
#-*-coding:utf-8 -*
#Python 3
#must have a valid gif file "im.gif" in the same foldeer
from tkinter import *
Window=Tk()
ListePhoto=list()
ListePhoto.append(PhotoImage(file="im.gif"))
def Try():
Window.title('image')
Window.geometry('+0+0')
Window.configure(bg='white')
DisplayImage()
def DisplayImage():
label_frame=LabelFrame(Window, relief='ridge', borderwidth=12, text="AnImage",
font='Arial 16 bold',bg='lightblue',fg='black')
ListeBouttons=list()#Liste Vide pour les Radiobutton(s)
RadioButton = Radiobutton(label_frame,text="notext",image=ListePhoto[0], indicatoron=0)
RadioButton.grid(row=1,column=1)
label_frame.pack(side="left")
if __name__ == '__main__':
Try()

Python Tkinker - showing a jpg as a class method not working

I'm trying to show a jpg image as background for a GUI thing I'm building.
I can get it to work in a single method:
from Tkinter import *
from PIL import Image, ImageTk
class MakeGUI(object):
master = None
w = None
def __init__(self):
self.canvasSizeY = 400 #height
self.canvasSizeX = 640 #width
def setupCanvas(self):
"""
preps the canvas for drawing.
"""
self.master = Tk()
self.w = Canvas(self.master, width=self.canvasSizeX, height=self.canvasSizeY)
self.w.config(bg='white')
image = Image.open("background.jpg")
photo = ImageTk.PhotoImage(image)
self.w.create_image(0,0, image=photo, anchor=NW)
self.w.pack()
mainloop()
def main():
makeGUI = MakeGUI()
makeGUI.setupCanvas()
if __name__ == '__main__':
main()
But when I try and make the canvas in one method, and show the canvas in another, it doesn't show the jpg (when I've been testing, I've created and shown & text and rectangles using this approach):
from Tkinter import *
from PIL import Image, ImageTk
class MakeGUI(object):
master = None
w = None
def __init__(self):
self.canvasSizeY = 400 #height
self.canvasSizeX = 640 #width
def setupCanvas(self):
"""
preps the canvas for drawing.
"""
self.master = Tk()
self.w = Canvas(self.master, width=self.canvasSizeX, height=self.canvasSizeY)
self.w.config(bg='white')
image = Image.open("background.jpg")
photo = ImageTk.PhotoImage(image)
self.w.create_image(0,0, image=photo, anchor=NW)
def showImage(self):
"""
pushes the image to the screen
"""
self.w.pack()
self.w.mainloop()
def main():
makeGUI = MakeGUI()
makeGUI.setupCanvas()
if __name__ == '__main__':
main()
I want to use the GUI dynamically to show some text as I work through some editing, so I'm interested to understand what I've got wrong before I get too far into the build in case its a showstopper...
The most obvious problem is that in the second case you are never calling showImage. Even after you do call that function, your image probably won't show up. Images will be garbage-collected if there isn't a reference to them. It may seem like there's a reference because you're adding it to a canvas, but that isn't enough.
You'll need to do something like:
self.photo = ImageTk.PhotoImage(image)
Finally, I recommend that you take the call to mainloop out of showImage. mainloop must always be called exactly once, so most typically it is the last line of code in your program, or the last line of code in your main function.
A more common way to make a Tkinter application is to subclass either the Tk object or a Frame object, rather than having your main application be a generic object. For example:
class MyApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
...
self.setupCanvas(...)
...
if __name__ == "__main__":
app = MyApp()
app.mainloop()

Categories

Resources