This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 2 years ago.
I am starting to program, in which I have to make a python graphical interface, in which by means of a button the jpg file is chosen and it is displayed in the interface, but I have had a problem, since the image is not displayed and in the terminal it does not detect any error and practically I go crazy here I leave the code
from PIL import Image, ImageTk
from tkinter import Tk, Frame, Button, Label, Text, filedialog, PhotoImage
class Application_BotonPath(Frame):
def __init__(self, master = None):
super().__init__(master, width = "1300", height = "950", bg = "old lace")
self.master = master
self.pack()
self.Panel()
self.widget()
def Panel(self):
self.frame_side = Frame(self, width = '300', height = '850', bg = 'sky blue').place(x = 20, y = 50)
self.frame_show = Frame(self, width = '900', height = '850').place(x = 360, y = 50)
def widget(self):
boton = Button(self.frame_side, text = "Abrir Imagen", command = self.cargar_imagen).place(x = 85, y = 60, width = 150, height = 30)
salida = Text(self.frame_side, state = "disable").place(x = 43, y = 110, width = 250, height = 700)
def cargar_imagen(self):
self.ruta_imagen = filedialog.askopenfilename(title = "Abrir", filetypes = [('Archivo png', '*.png'), ('Archivo jpeg', '*.jpg')])
load = Image.open(self.ruta_imagen)
imagen = ImageTk.PhotoImage(load)
label = Label(self.frame_show, image = imagen)
label.place(x=0, y=0)
root = Tk()
root.wm_title("Detector de Caracteres")
app = Application_BotonPath(root)
app.mainloop()
image
This is what I get, the gray box that is in the upper right I suppose it is the image, but it does not show it. please help
Welcome to SO.
The image is created in a function, and when the function ends the reference to the image is garbage collected. Therefore the Label can not find any image.
You can save a reference to the image in the label object:
label = Label(self.frame_show, image = imagen)
label.image = imagen # Save reference to image
or you can make the reference an attribute of the instance:
self.imagen = ImageTk.PhotoImage(load)
label = Label(self.frame_show, image = self.imagen)
Related
I tried to build off of the solution here. My code is:
from tkinter import mainloop, Tk, Frame, Button, Label, Canvas, PhotoImage, NW
from tkinter import ttk
from tkinter import filedialog
import tkinter as tk
from PIL import Image, ImageTk
class my_class(tk.Tk):
def __init__(self):
super().__init__()
self.geometry=('1400x1400')
self.filename = ''
my_notebook = ttk.Notebook(self)
my_notebook.pack(pady=5)
self.selections = Frame(my_notebook, width = 1100, height = 700)
self.selections.pack(fill = "both", expand=1)
my_notebook.add(self.selections, text = "Selections")
Button(self.selections, text = "Select an Image", command = self.get_image).place(x=10,y=40)
self.image_frame = Frame(my_notebook, width = 1100, height = 700)
self.image_frame.pack(fill = "both", expand=1)
my_notebook.add(self.image_frame, text = "Image")
self.my_canvas = Canvas(self.image_frame, width=800, height=600, bg="white")
self.my_canvas.pack()
self.rgb_var = tk.StringVar(self.image_frame, '0 0 0')
self.rgb_label = tk.Label(self.image_frame, textvariable = self.rgb_var)
self.rgb_label.pack()
self.image_frame.bind('<Motion>', lambda e: self.get_rgb(e))
def get_image(self):
self.filename = filedialog.askopenfilename(initialdir="D:/Python", title="select a file", filetypes = (("png files","*.png"),("jpg files","*.jpg")))
self.img = Image.open(self.filename)
self.img_rgb = self.img.convert('RGB')
dim_x, dim_y = self.img_rgb.size
self.img_tk = ImageTk.PhotoImage(self.img_rgb.resize((dim_x, dim_y)))
self.my_canvas.create_image(dim_x // 2, dim_y // 2, image = self.img_tk)
def get_rgb(self, event):
x, y = event.x, event.y
try:
rgb = self.img_rgb.getpixel((x, y))
self.rgb_var.set(rgb)
except IndexError:
pass # ignore errors if cursor is outside the image
if __name__ == '__main__':
app = my_class()
app.geometry=('1200x900')
app.mainloop()
I can use the button to select an image. Then I click the (Image) tab and see the selected image on the canvas.
I expected the (rgb_var) displayed under the image to update as I move the mouse pointer across the image. Instead the numbers under the image only update when the mouse pointer is in the frame, but outside the canvas. Also the numbers displayed seem to be unrelated to pixels in the image. How can I display the RGB values of a pixel that is (under the mouse pointer) when the mouse pointer is over the image?
I am having issues trying to place a frame within a frame using classes/objects with python/tkinter. My goal is to simply place a frame in the north west corner of the outer frame instead of the whole window itself. I think I'm incorrectly referencing the outer frame in the inner frame class but I'm not 100% sure. I am fairly new to OOP and tkinter so forgive my ignorance and I appreciate the help.
Sample code:
from tkinter import *
class window():
def __init__(self, master):
self.master = master.minsize(500, 500)
master.maxsize(500,500)
self.outer_frame = Frame(master, width = 250, height = 250, bg = "red").place(anchor = CENTER, relx = 0.5, rely = 0.5)
def create_inner_window(self):
self.inner_frame = inner_frame(self.outer_frame)
class inner_frame():
def __init__(self, outer_frame):
self.inner_frame = Frame(master = outer_frame, width = 125, height = 125, bg = "blue").place(anchor = NW)
root = Tk()
my_window = window(root)
my_window.create_inner_window()
root.mainloop()
What I'm trying to accomplish:
What I get instead:
This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 6 years ago.
i'm making a monopoly game, & i am trying to draw image on canvas, but it will only work if not in function:
def make_image(root, location, canvas):
photo = PhotoImage(file = root)
canvas.create_image(location["X"],location["Y"], image = photo, anchor = "nw")
class something():
def start(self, controller):
self.controller = controller
#photo = PhotoImage(file = "googolopoly.png")
#self.canvas.create_image(0,0, image = photo, anchor = "nw")
make_image("googolopoly.png", {"X":0,"Y":0}, self.canvas)
make_text(self.canvas, "MONOPOLY!!!!", {"X":1050,"Y":20})
make_button(self.main_tk, self.canvas, "roll dice", lambda: self.roll_dice(), {"X":1100, "Y":50}, 100)
for i in range(controller.player_number):
self.players.append(make_text(self.canvas, str(i+1), {"X":902+i*10, "Y":946}))
self.main_tk.mainloop()
currently it won't draw a picture, but if i get down the comments it will work (no function)
it also happens after main loop, when i want to draw players
i really need it as a function. what to do? if you need i can put some more code
You were missing this line of code: myCanvas.image = photo.
And even if it would be easier to draw the image on a Label, with this code you can do it on a Canvas with the function make_image():
from Tkinter import *
def make_image(filename, location, canvas):
photo = PhotoImage(file=filename)
myCanvas.image = photo
myCanvas.create_image(0,0, image = photo, anchor = "nw")
root = Tk()
myCanvas = Canvas(root, width=100, height=100)
myCanvas.grid()
make_image("image.gif", (5,5,95,95), myCanvas)
root.mainloop()
My aim is to create a random country generator, and the flag of the country that is picked will appear. However, if the image file is bigger than the predetermined size of the label, then only part of the image is displayed. Is there a way of resizing the image to fit the label? (All other questions like this which I have seen have been answered, mentioning the PIL or Image modules. I tested them both, and they both came up with this error:
Traceback (most recent call last):
File "C:\python\country.py", line 6, in
import PIL
ImportError: No module named 'PIL'
This is my code, if it helps:
import tkinter
from tkinter import *
import random
flags = ['England','Wales','Scotland','Northern Ireland','Republic of Ireland']
def newcountry():
country = random.choice(flags)
flagLabel.config(text=country)
if country == "England":
flagpicture.config(image=England)
elif country == "Wales":
flagpicture.config(image=Wales)
elif country == "Scotland":
flagpicture.config(image=Scotland)
elif country == "Northern Ireland":
flagpicture.config(image=NorthernIreland)
else:
flagpicture.config(image=Ireland)
root = tkinter.Tk()
root.title("Country Generator")
England = tkinter.PhotoImage(file="england.gif")
Wales = tkinter.PhotoImage(file="wales.gif")
Scotland = tkinter.PhotoImage(file="scotland.gif")
NorthernIreland = tkinter.PhotoImage(file="northern ireland.gif")
Ireland = tkinter.PhotoImage(file="republic of ireland.gif")
blackscreen = tkinter.PhotoImage(file="black screen.gif")
flagLabel = tkinter.Label(root, text="",font=('Helvetica',40))
flagLabel.pack()
flagpicture = tkinter.Label(root,image=blackscreen,height=150,width=150)
flagpicture.pack()
newflagButton = tkinter.Button(text="Next Country",command=newcountry)
newflagButton.pack()
The code works perfectly fine apart from only showing part of the image. Is there a way to resize the images within the code itself?(I am using Python 3.5.1)
If you don't have PIL installed, first you need to install
pip install pillow
Once installed you can now import from PIL:
from PIL import Image, ImageTk
Tk's PhotoImage can only display .gif's, whereas PIL's ImageTk will let us display various image formats in tkinter and PIL's Image class has a resize method we can use to resize the image.
I trimmed your code down some.
You can resize the image and then just configure the label, the label will expand to be the size of the image. If you gave the label a specific height and width, lets say height=1 and width=1 and you resized the image to be 500x500 and then configured the widget. It would still display a 1x1 label since you've set these attributes explicitly.
In the below code, modifiying the dict, it is not okay to modify a dict while iterating over it. dict.items() returns a copy of the dict.
There's various ways to do this, I just though a dict was convenient here.
Link to an image that's over the height / width limit - kitty.gif
from tkinter import *
import random
from PIL import Image, ImageTk
WIDTH, HEIGHT = 150, 150
flags = {
'England': 'england.gif',
'Wales': 'wales.gif',
'Kitty': 'kitty.gif'
}
def batch_resize():
for k, v in flags.items():
v = Image.open(v).resize((WIDTH, HEIGHT), Image.ANTIALIAS)
flags[k] = ImageTk.PhotoImage(v)
def newcountry():
country = random.choice(list(flags.keys()))
image = flags[country]
flagLabel['text'] = country
flagpicture.config(image=image)
if __name__ == '__main__':
root = Tk()
root.configure(bg='black')
batch_resize()
flagLabel = Label(root, text="", bg='black', fg='cyan', font=('Helvetica',40))
flagLabel.pack()
flagpicture = Label(root)
flagpicture.pack()
newflagButton = Button(root, text="Next Country", command=newcountry)
newflagButton.pack()
root.mainloop()
Instead of randomly selecting a country to display its flag, we loop through the flags dictionary that is key-sorted. Unlike the random choice which will inevitably repeat the flags, this scheme runs through the countries in alphabetical order. Meanwhile, we resize all the images to a fixed pixel size based on the width and height of the root window multiplied by a scale factor. Below is the code:
import tkinter as tk
from PIL import Image, ImageTk
class Flags:
def __init__(self, flags):
self.flags = flags
self.keyList = sorted(self.flags.keys()) # sorted(flags)
self.length = len(self.keyList)
self.index = 0
def resize(self, xy, scale):
xy = [int(x * y) for (x, y) in zip(xy, scale)]
for k, v in self.flags.items():
v = Image.open(r'C:/Users/user/Downloads/' + v)
v = v.resize((xy[0], xy[1]), Image.ANTIALIAS)
self.flags[k] = ImageTk.PhotoImage(v)
def newCountry(self, lbl_flag, lbl_pic):
country = self.keyList[self.index]
lbl_flag["text"] = country
img = self.flags[country]
lbl_pic.config(image = img)
self.index = (self.index + 1) % self.length # loop around the flags dictionary
def rootSize(root):
# Find the size of the root window
root.update_idletasks()
width = int(root.winfo_width() * 1.5) # 200 * m
height = int(root.winfo_height() * 1.0) # 200 * m
return width, height
def centerWsize(root, wh):
root.title("Grids layout manager")
width, height = wh
# Find the (x,y) to position it in the center of the screen
x = int((root.winfo_screenwidth() / 2) - width/2)
y = int((root.winfo_screenheight() / 2) - height/2)
root.geometry("{}x{}+{}+{}".format(width, height, x, y))
if __name__ == "__main__":
flags = {
"Republic of China": "taiwan_flag.png",
"United States of America": "america_flag.gif",
"America": "america_flag.png",
}
root = tk.Tk()
wh = rootSize(root)
centerWsize(root, wh)
frame = tk.Frame(root, borderwidth=5, relief=tk.GROOVE)
frame.grid(column=0, row=0, rowspan=3)
flag = Flags(flags)
zoom = (0.7, 0.6) # Resizing all the flags to a fixed size of wh * zoom
flag.resize(wh, zoom)
lbl_flag = tk.Label(frame, text = "Country name here", bg = 'white', fg = 'magenta', font = ('Helvetica', 12), width = 30)
lbl_flag.grid(column = 0, row = 0)
pic_flag = tk.Label(frame, text = "Country flag will display here")
pic_flag.grid(column = 0, row = 1)
btn_flag = tk.Button(frame, text = "Click for next Country Flag",
bg = "white", fg = "green", command = lambda : flag.newCountry(lbl_flag, pic_flag))
btn_flag.grid(column = 0, row = 2)
root.mainloop()
You can use the PIL(pillow module to resize the image)
But in order to resize the images to exactly to the widget size, You can do the following. (Assuming that you are familiar with basic tkinter syntax structure)
your_widget.update() #We are calling the update method in-order to update the
#widget size after it's creartion, Other wise, it will just print '1' and '1'
#rather than the pixel size.
height=your_widget.winfo_height()
width=your_widget.winfo_width()
print(height,weight)
Now you can use the height and width information to create a new image that you can size it perfectly to your widget.
But if you have your image is already created, you can use the PIL module to resize the image to your size
first open your image with
flag_temp = Image.open("file location")
next resize the image to your size
flag_new = flag_temp.resize((10,10))# example size
make your final image to add in your widget
flag_final = ImageTk.PhotoImage(flag_new)
now you can use the 'flag final' varible in your widget.
IF YOUR APP HAS TO BE RESIZED AT ANY POINT, you can use the height and width varible created in the first code para, to dynamically resize the image
But you should make sure that the function is called regularly to update it.
You should also pass in the height and width variable in the place of (10,10) something like this
flag_new = flag_temp.resize((height,widht)
Hopefully this was helpful, I think the answer is bit long for your question, If you have any problems pls comment below.
I'm trying to implement simple image viewer, where you can choose from 2 pictures. I have one menubutton which offers these pictures. After choosing one of the images, the program creates 3 or 5 buttons. I would like to append to each of these buttons different images, so the first button would have one image and the second button would have another image and so on. I've created a function with for loop to create these buttons, but can't move on from that point. I can append one image to all of them, but can't do that one by one with different images.
Thanks for help
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
from functools import partial
from PIL import Image, ImageTk
class Halabala():
def __init__(self):
self.master = tk.Tk()
self.master.geometry("1100x700")
self.lists_labels = []
self.rbutton = tk.Menubutton(self.master, text = "Choose picture")
self.picks2 = tk.Menu(self.rbutton)
self.rbutton.config(menu=self.picks2)
self.picks2.add_command(label = "Spider", command = partial(self.create_labels,3))
self.picks2.add_command(label = "Sugar", command = partial(self.create_labels,5))
self.rbutton.config(width = 30, bg = "white", bd = 5, relief = tk.RAISED)
self.rbutton.place(x = 900, y = 30)
self.master.mainloop()
def create_labels(self, num):
self.picture = Image.open("blue.gif")
self.picture.thumbnail((130,130))
self.tkim = ImageTk.PhotoImage(self.picture)
for label in self.lists_labels:
label.destroy()
self.lists_labels=[]
for i in range(num):
but = tk.Button(self.master, image = self.tkim)
but.grid(row = i + 1, column = 0)
self.lists_labels.append(but)
myapp = Halabala()
This is the code relevant for your question:
class Halabala():
def __init__(self):
.............
self.pictures = ["pavuk1", "pavuk2", "pavuk3"]
self.lists_labels = []
self.lists_images = []
self.init_image_list()
............
def init_image_list(self):
for i in self.pictures:
picture = Image.open(i)
picture.thumbnail((130, 130))
self.lists_images.append(ImageTk.PhotoImage(picture))
def create_labels(self, num):
for label in self.lists_labels:
label.destroy()
self.lists_labels=[]
for i in range(num):
but = tk.Button(self.master, image = self.lists_images[i])
but.grid(row = i + 1, column = 0)
self.lists_labels.append(but)