I am new to this site, and I am trying to create a simple image viewer in Python 2.7 using Tkinter, But when I try to load an image in it,it does not show anything!, I bet it is something embarassingly obvious, but I dont know what's wrong. I am using Windows XP. Here's my code:
from Tkinter import *
import tkFileDialog
from PIL import ImageTk, Image
root = Tk(className="Image viewer")
canvas_width = 800
canvas_height = 600
root.config(bg="white")
def openimage():
picfile = tkFileDialog.askopenfilename()
img = ImageTk.PhotoImage(file=picfile)
canvas.create_image(0,0, anchor=NW, image=img)
yscrollbar = Scrollbar(root)
yscrollbar.pack(side=RIGHT, fill=Y)
xscrollbar = Scrollbar(root, orient=HORIZONTAL)
xscrollbar.pack(side=BOTTOM, fill=X)
canvas = Canvas(root, width=canvas_width, height=canvas_height, yscrollcommand=yscrollbar.set, xscrollcommand=xscrollbar.set)
button = Button(root,text="Open",command=openimage)
button.pack(side=BOTTOM)
canvas.pack(side=TOP)
yscrollbar.config(command=canvas.yview)
xscrollbar.config(command=canvas.xview)
mainloop()
Update: It works when i remove the file browser, and give it the path to a file, but i want the file browser, and using a label works, but scroll bars dont work with it, and i want to be able to scroll the picture.
I found on "The Tkinter PhotoImage Class" that PhotoImage can't be assigned to local variable in function because garbage collector remove it.
So you can use global variable:
img = None
def openimage():
global img
picfile = tkFileDialog.askopenfilename()
img = ImageTk.PhotoImage(file=picfile)
canvas.create_image(0,0, anchor=NW, image=img)
or assign image to existing widget (for example canvas)
def openimage():
picfile = tkFileDialog.askopenfilename()
canvas.img = ImageTk.PhotoImage(file=picfile)
canvas.create_image(0,0, anchor=NW, image=canvas.img)
by the way: you should check if file was selected
def openimage():
picfile = tkFileDialog.askopenfilename()
if picfile:
canvas.img = ImageTk.PhotoImage(file=picfile)
canvas.create_image(0,0, anchor=NW, image=canvas.img)
add scrollregion and you have file viewer with working scrollbars
def openimage():
picfile = tkFileDialog.askopenfilename()
if picfile:
canvas.img = ImageTk.PhotoImage(file=picfile)
canvas.create_image(0,0, anchor=NW, image=canvas.img)
canvas.configure(canvas, scrollregion=(0,0,canvas.img.width(),canvas.img.height()))
Dont know about problem in your code but You can use this function in place of your one:
def openimage():
try:
Artwork.destroy()
except Exception:
pass
picfile = tkFileDialog.askopenfilename()
img = ImageTk.PhotoImage(file=picfile)
#canvas.create_image(0,0, anchor=NW, image=img)
Artwork=Label(root,image=img)
Artwork.img=img
Artwork.pack(side=BOTTOM)#do packing urself
Note that is is the minimal implementation.
Related
I have made a background for my GUI in inkscape and have managed to add a transparent image over the top to use as buttons but cant figure out how to make them run a subroutine (nav) when clicked. I either need an image with transparency over the top of my background that I can click or a completely see through rectangle that I can position over a button drawn on the background image in inkscape. I'm on Ubuntu if it matters.
from tkinter import *
from PIL import ImageTk, Image
import sys
root = Tk ()
root.title('GUI')
root.geometry("1000x564")
root.attributes('-zoomed', True)
root.attributes("-type", "splash")
#define image
bg = ImageTk.PhotoImage(file="BACKGROUND.png")
#create canvas
my_canvas = Canvas(root, width=800, height=500)
my_canvas.pack(fill="both", expand=True)
my_canvas.create_image(0,0, image=bg, anchor = NW)
def nav():
print ("navigation")
#creating button which supports png transparency
#button = PhotoImage(file="button2.png")
#my_canvas.create_image(260,-70, anchor=NW, image=button, state='normal', )
buttonImage = ImageTk.PhotoImage(Image.open("button.png"))
button = my_canvas.create_image(50, 50, image=buttonImage)
my_canvas.tag_bind(Button, "<Button-1>", nav())
def resizer(e):
global bg1, resized_bg, new_bg
# open image
bg1 = Image.open("BACKGROUND.png")
# resize
resized_bg =bg1.resize((e.width, e.height), Image.ANTIALIAS)
#DEFINE IMAGE AGAIN
new_bg =ImageTk.PhotoImage(resized_bg)
#add back to the canvas
my_canvas.create_image(0,0, image=new_bg, anchor = NW)
# my_canvas.create_image(260,-70, anchor=NW, image=button, state='normal', )
button = my_canvas.create_image(50, 50, image=buttonImage)
def close(e):
root.destroy()
root.bind('<Configure>', resizer)
root.bind('<Escape>', close)
root.mainloop()
when calling function with my_canvas.tag_bind(button, "<Button-1>", nav) nav(root) is actually being called when clicked so def nav(root): has to be used for the sub routine to run correctly.
I want to show images in the Listbox tkinter widget. My code looks like this:
mylist = Listbox(self.labelFrame3, yscrollcommand=self.yscrollbar.set, selectmode=SINGLE)
mylist.grid(row=0, column=0, rowspan=21, columnspan=21, sticky=(N, S, E, W))
img = Image.open('modeldata/photosamples/amanullahattamuhammad2.0.jpg') # PIL solution
img = img.resize((200, 200), Image.ANTIALIAS) # The (250, 250) is (height, width)
img = ImageTk.PhotoImage(img)
How to print this image in Listbox?
As someone mentioned in a comment you can't put images in a Listbox, but as I mentioned in another, you could use a Text widget instead because you can put images into them. Below is a relatively simple demonstration of how something like that can be done. Its two buttons illustrate how it can display just text or a combination of the two simultaneously. Text widget are actually very versatile.
Anyway, since presumably you want a scrollable list, the Text subclass named tkinter.scrolledtext is used instead of plain one to save work. Since it's a subclass, it can do anything its baseclass can do.
from pathlib import Path
from PIL import Image, ImageTk
import tkinter as tk
from tkinter.constants import *
from tkinter.scrolledtext import ScrolledText
class App:
def __init__(self, image_folder_path, image_file_extensions):
self.root = tk.Tk()
self.image_folder_path = image_folder_path
self.image_file_extensions = image_file_extensions
self.create_widgets()
self.root.mainloop()
def create_widgets(self):
self.list_btn = tk.Button(self.root, text='List Images', command=self.list_images)
self.list_btn.grid(row=0, column=0)
self.show_btn = tk.Button(self.root, text='Show Images', command=self.show_images)
self.show_btn.grid(row=1, column=0)
self.text = ScrolledText(self.root, wrap=WORD)
self.text.grid(row=2, column=0, padx=10, pady=10)
self.text.image_filenames = []
self.text.images = []
def list_images(self):
''' Create and display a list of the images the in folder that have one
of the specified extensions. '''
self.text.image_filenames.clear()
for filepath in Path(self.image_folder_path).iterdir():
if filepath.suffix in self.image_file_extensions:
self.text.insert(INSERT, filepath.name+'\n')
self.text.image_filenames.append(filepath)
def show_images(self):
''' Show the listed image names along with the images themselves. '''
self.text.delete('1.0', END) # Clear current contents.
self.text.images.clear()
# Display images in Text widget.
for image_file_path in self.text.image_filenames:
img = Image.open(image_file_path).resize((64, 64), Image.ANTIALIAS)
img = ImageTk.PhotoImage(img)
self.text.insert(INSERT, image_file_path.name+'\n')
self.text.image_create(INSERT, padx=5, pady=5, image=img)
self.text.images.append(img) # Keep a reference.
self.text.insert(INSERT, '\n')
image_folder_path = 'modeldata/photosamples'
image_file_extensions = {'.jpg', '.png'}
App(image_folder_path, image_file_extensions)
Here's it running on a folder on my computer with the images shown:
New to python and so far mostly love it but this issue is odd. The exact same code works from the root but not in a method.
This does not render the image:
from tkinter import *
root = Tk()
def draw():
print("does not work")
canvas = Canvas(root, width = 300, height = 300)
canvas.pack()
img = PhotoImage(file="Db.png")
canvas.create_image(20,20, anchor=NW, image=img)
draw()
mainloop()
But this works fine:
from tkinter import *
root = Tk()
print("This works fine")
canvas = Canvas(root, width = 300, height = 300)
canvas.pack()
img = PhotoImage(file="Db.png")
canvas.create_image(20,20, anchor=NW, image=img)
mainloop()
Any help would be appreciated.
As martineau explains in the comments above the problem with the code is that the img variable only exists while the function is processing, it is deleted after the function returns and it's required that I keep a reference to the image object. Making it a global variable corrects the issue.
Many Thanks!
I want to put a background image in a Frame, this is the code that I'm trying to run without success.
import tkinter as tk
from tkinter import *
root = tk.Tk()
F1 = Frame(root)
F1.grid(row=0)
photo = PhotoImage(file="sfondo.png")
label = Label(F1, image=photo)
label.image = photo
label.place(x=0, y=0)
b = tk.Button(label, text="Start")
b.grid(row=8, column=8)
root.mainloop()
If I run the code as this, only a little point in the top left corner is displayed (the frame without nothing in, even if I placed the label inside of it). If I replace the label parent with root, it displays the button with a little part of the image as backgound (only the perimeter of the button is colored for a few pixels). However what I want is a full displayed background image in the frame where I can put the widgets that I want.
I tried to with the place method as this and PIL module
import tkinter as tk
from tkinter import *
from PIL import Image, ImageTk
root = tk.Tk()
F1 = Frame(root)
F1.grid(row=0)
image = Image.open("sfondo.png")
render = ImageTk.PhotoImage(image)
img = tk.Label(F1, image=render)
img.image = render
img.place(x=0, y=40)
b = tk.Button(img, text="Start")
b.grid(row=8, column=8)
root.mainloop()
Here more or less I'm having the same problems, if I set the parent of the label to root, the button is displayed with the perimeter coloured.
If I set the parent to F1 nothing happens and in both cases if I set the parent as root and remove the button, the image is fully displayed.
But what I want is that the image is fully displayed in the frame and after diplay on the background image the widgets.
You could put an image on a Canvas, and then place a Button on that by putting it inside a Canvas window object which can hold any Tkinter widget.
Additional widgets can be added in a similar fashion, each inside its own Canvas window object (since they can hold only a single widget each). You can workaround that limitation by placing a Frame widget in the Canvas window, and then putting other widgets inside it.
Here's an example showing how to display a single Button:
from PIL import Image, ImageTk
import tkinter as tk
IMAGE_PATH = 'sfondo.png'
WIDTH, HEIGTH = 200, 200
root = tk.Tk()
root.geometry('{}x{}'.format(WIDTH, HEIGHT))
canvas = tk.Canvas(root, width=WIDTH, height=HEIGTH)
canvas.pack()
img = ImageTk.PhotoImage(Image.open(IMAGE_PATH).resize((WIDTH, HEIGTH), Image.ANTIALIAS))
canvas.background = img # Keep a reference in case this code is put in a function.
bg = canvas.create_image(0, 0, anchor=tk.NW, image=img)
# Put a tkinter widget on the canvas.
button = tk.Button(root, text="Start")
button_window = canvas.create_window(10, 10, anchor=tk.NW, window=button)
root.mainloop()
Screenshot:
Edit
While I don't know of a way to do it in Frame instead of a Canvas, you could derive your own Frame subclass to make adding multiple widgets easier. Here's what I mean:
from PIL import Image, ImageTk
import tkinter as tk
class BkgrFrame(tk.Frame):
def __init__(self, parent, file_path, width, height):
super(BkgrFrame, self).__init__(parent, borderwidth=0, highlightthickness=0)
self.canvas = tk.Canvas(self, width=width, height=height)
self.canvas.pack()
pil_img = Image.open(file_path)
self.img = ImageTk.PhotoImage(pil_img.resize((width, height), Image.ANTIALIAS))
self.bg = self.canvas.create_image(0, 0, anchor=tk.NW, image=self.img)
def add(self, widget, x, y):
canvas_window = self.canvas.create_window(x, y, anchor=tk.NW, window=widget)
return widget
if __name__ == '__main__':
IMAGE_PATH = 'sfondo.png'
WIDTH, HEIGTH = 350, 200
root = tk.Tk()
root.geometry('{}x{}'.format(WIDTH, HEIGTH))
bkrgframe = BkgrFrame(root, IMAGE_PATH, WIDTH, HEIGTH)
bkrgframe.pack()
# Put some tkinter widgets in the BkgrFrame.
button1 = bkrgframe.add(tk.Button(root, text="Start"), 10, 10)
button2 = bkrgframe.add(tk.Button(root, text="Continue"), 50, 10)
root.mainloop()
Result:
Update
It recently dawned on me that there actually is a simpler way to do this than creating a custom Frame subclass as shown in my previous edit above. The trick is to place() a Label with image on it in the center of the parent Frame — you are then free to use other geometry managers like pack() and grid() as you normally would — as illustrated in the sample code below. Not only is it less complicated, it's also a more "natural" way of adding widgets than needing to call a non-standard method such as add().
from PIL import Image, ImageTk
import tkinter as tk
IMAGE_PATH = 'sfondo.png'
WIDTH, HEIGHT = 250, 150
root = tk.Tk()
root.geometry('{}x{}'.format(WIDTH, HEIGHT))
# Display image on a Label widget.
img = ImageTk.PhotoImage(Image.open(IMAGE_PATH).resize((WIDTH, HEIGHT), Image.ANTIALIAS))
lbl = tk.Label(root, image=img)
lbl.img = img # Keep a reference in case this code put is in a function.
lbl.place(relx=0.5, rely=0.5, anchor='center') # Place label in center of parent.
# Add other tkinter widgets.
button = tk.Button(root, text="Start")
button.grid(row=0, column=0)
button = tk.Button(root, text="Continue")
button.grid(row=0, column=1, padx=10)
root.mainloop()
Result#2
P.S. You can download a copy of the sfondo.png background image from here.
This seems like a pretty straightforward question, but i am having trouble displaying a jpg image when a button is clicked. Here is my code (without the button code for the sake of time):
from tkinter import *
#screen stuff here
canvas = Canvas(app)
canvas.grid(row = 0,column = 0)
photo = PhotoImage(file = "test.jpg")
canvas.create_image(0,0, image = photo)
def show_image():
global canvas
global photo
canvas.create_image(0,0, image = photo)
#button that calls the function down here
Thanks!
This works with Python2:
import Tkinter as tk
import ImageTk
def show_image():
x = canvas.create_image(125, 125, image=tk_img)
while True:
print('show')
canvas.itemconfigure(x, state=tk.NORMAL)
button.configure(text = 'Hide')
yield
print('hide')
canvas.itemconfigure(x, state=tk.HIDDEN)
button.configure(text = 'Show')
yield
root = tk.Tk()
canvas = tk.Canvas(root, width=250, height=250)
canvas.grid(row=0, column=0)
tk_img = ImageTk.PhotoImage(file='image.png')
button = tk.Button(
root, text="Show", command=show_image().next, anchor='w',
width=10, activebackground="#33B5E5")
button.grid(row=1, column=0)
root.mainloop()
In Python3, PhotoImage can open GIF, PPM/PGM images. To open other formats, you may need to install Pillow (a fork of the PIL project for Python3).