TkInter script vs class - Canvas behaviour [duplicate] - python

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 7 years ago.
I'm using TkInter to write a GUI that will contain an image and a few buttons in a panel next to the image.
I started by writing a script that would allow me to visualize an image, and it works just fine:
#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
import Tkinter
from PIL import Image, ImageTk
window = Tkinter.Tk()
window.title("Test GUI")
window.geometry("640x478")
window.configure(background='grey')
window.grid()
img = ImageTk.PhotoImage(Image.open('./test.jpg'))
canvas = Tkinter.Canvas(window, width=640, height=478, bg='white')
canvas.create_image(0,0,anchor='nw',image=img)
canvas.grid(column=0,row=0)
window.mainloop()
I then tried to rewrite the above code as a class, to implement some event-handling functions. However, the same exact code written in the class initialization function will not visualize the image.
#!/usr/bin/python
# -*- coding: iso-8859-1 -*-
import Tkinter
from PIL import Image, ImageTk
class showImageGUI(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
# the grid layout manager is a simple grid
# where you put your widgets
self.grid()
img = ImageTk.PhotoImage(Image.open('./test.jpg'))
canvas = Tkinter.Canvas(self, width=640, height=478, bg='white')
canvas.create_image(0,0,anchor='nw',image=img)
canvas.grid(column=0,row=0)
if __name__ == "__main__":
app = showImageGUI(None)
app.title('Test GUI')
# event-driven programming: the program will
# loop forever doing nothing but wait for events
# and only react when it receives an event
app.mainloop()
The only difference between the two is:
In the script implementation I assign the parent of the canvas widget to be the whole window.
In the class implementation I assign the parent of the canvas widget to be the self variable for the whole app.
Can someone please explain me why is this breaking the code / how to solve it?

There's a bug in Tkinter that causes images to disappear if there is no external reference to them, even though they should be bound into the Canvas widget somehow. I'm probably not explaining this well, because I've never taken the trouble to really research what is going on. I believe it is explained somewhere on effbot.org.
In any event, change the line
img = ImageTk.PhotoImage(Image.open('./test.jpg'))
to
img = self.img = ImageTk.PhotoImage(Image.open('./test.jpg'))
and I think it will work for you. It works for me.

Related

How can I load an image into tkinter? [duplicate]

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed last year.
I'm trying to load an image into tkinter, to use as a background image. The image is a GIF (originally JPG, but I heard that tkinter doesn't support that format) with the same dimensions as the window. Anyway, when I ran my code, it ran, but the tkinter window was empty! Here's my code for the window:
class Window(Tk):
def __init__(self):
super().__init__()
self.geometry("700x600")
self.resizable(False, False)
def background_img(self, img_path):
background_img = PhotoImage(file=img_path)
background_img_label = Label(self, image=background_img)
background_img_label.place(x=0, y=0)
window = Window()
img_path = "background.gif"
window.background_img(img_path)
window.mainloop()
Can you please tell me what I'm doing wrong? Thanks in advance.
As TDG said, the names background_img (function) and background_img (tkinter.PhotoImage) override each other. You should rename one.

How to display multiple images inside tkinter window?

I want to display 7 different images and plot them inside tkinter window. I only know to display it using OpenCV which actually displays the image outside the Tkinter GUI window. How to plot the images inside the GUI window?
Tkinter GUI:
I advise you read the documentation of tkinter as it has tons of example on how to achieve a soluction to your problem. I have made a sample GUI which updates image on the GUI with a randomized pixel picture. Note that there are a lot of different approaches how to do this. In my case I have made a class in which I display a frame and a button. The button calls a function to randomize the image (or changes to the next one in your case) and calls the function to update the frame with a new image. Hope it gives you a jump start. Cheers!
P.S.: for multiple images use more labels and functions;)
Code:
import tkinter as tk
from tkinter import *
import cv2
import numpy as np
from PIL import Image, ImageTk
class DisplayImage:
def __init__(self, master):
self.master = master
master.title("GUI")
self.image_frame = Frame(master, borderwidth=0, highlightthickness=0, height=20, width=30, bg='white')
self.image_frame.pack()
self.image_label = Label(self.image_frame, highlightthickness=0, borderwidth=0)
self.image_label.pack()
self.Next_image = Button(master, command=self.read_image, text="Next image", width=17, default=ACTIVE, borderwidth=0)
self.Next_image.pack()
def display_image(self, event=None):
self.cv2image = cv2.cvtColor(self.img, cv2.COLOR_BGR2RGBA)
self.from_array = Image.fromarray(self.cv2image)
self.imgt = ImageTk.PhotoImage(image=self.from_array)
self.image_label.configure(image=self.imgt)
def read_image(self, event=None):
self.img = np.random.randint(255, size=(250,250,3),dtype=np.uint8)
self.master.after(10, self.display_image)
def main():
root = tk.Tk()
GUI = DisplayImage(root)
GUI.read_image()
root.mainloop()
if __name__ == '__main__':
main()
Output:
If you are OK with using a wrapper with tkinter, then PySimpleGUI is a good choice.
There was a new Demo application posted this week that demonstrates how to show a webcam in a GUI window. There's another Demo posted that plays back a video file using OpenCV, again in a GUI window.
The code that generated that screen shot can be found here:
Open and Play Video Using PySimpleGU + OpenCV
You can start with the Demo and expand it by adding more buttons.

How to put image in another window in tkinter?

I want to put an image in the second window using tkinter, in the first window the code works good, but the second window shows nothing.
In this part I import necessary modules:
from tkinter import filedialog, Tk, Frame, Label, PhotoImage, Button
from PIL import Image
from tkinter import*
import tkinter as tk
Then create the principal window:
raiz = Tk()
raiz.title("ventana")
Then I create the frame and put the image in the frame:
miFrame = Frame()
miFrame.pack()
miFrame.config(width="1400", heigh=("1200"))
fondo=tk.PhotoImage(file="fondoF.png")
fondo=fondo.subsample(1,1)
label=tk.Label(miFrame,image=fondo)
label.place(x=0,y=0,relwidth=1.0,relheight=1.0)
Then a button that will call the second window function:
btn3 = Button(raiz, text="boton")
btn3.place(x=500, y=500)
btn3.config(command=abrirventana2)
Here we have the function which opens the second window and here (I guess) is where I want to put the image.
This part also has two buttons named mih which does nothing in the meantime and ok which calls the function to close the second window:
def abrirventana2():
raiz.deiconify()
ventana2=tk.Toplevel()
ventana2.geometry('500x500')
ventana2.title("ventana2")
ventana2.configure(background="white")
fondov=tk.PhotoImage(file="xxx.gif")
label1=tk.Label(ventana2,image=fondov)
label1.place(x=50,y=50,relwidth=5.0,relheight=5.0)
mensaje=tk.Label(ventana2,text="funciona")
mensaje.pack(padx=5,pady=5,ipadx=5,ipady=5,fill=tk.X)
boton1=tk.Button(ventana2,text='mih')
boton1.pack(side=tk.TOP)
boton2=tk.Button(ventana2,text='ok',command=ventana2.destroy)
boton2.pack(side=tk.TOP)
Function to close the second window:
def cerrarventana2():
ventana.destroy()
I use the mainloop to keep the window open
raiz.mainloop()
Note: I had already tried creating a frame in the second window, but it didn't work.
Apologies for my previously incorrect answer.
The reason the image is not showing is due to the fact that you did not create a reference to it. If you don't create a reference, the image is garbage collected, which doesn't remove it, but in a sense just renders a blank placeholder on the GUI.
In order to display the image correctly you need to add a reference to the image within the code that displays the image.
You therefore now have:
fondov=tk.PhotoImage(file="giphy.gif")
label1=tk.Label(ventana2,image=fondov)
label1.image = fondov
label1.pack()
(label1.image = fondov is the reference)
Sorry for the confusion there. This should work.

Display Google Map API in Python Tkinter window

Hi I am working on Google Map API in Python. I am using the source code which can be found at this website
This code when compiled produces a 'htm' file showing a Google Map with the markers placed on the map.
So I have created a Window Frame shown below:
from Tkinter import * # order seems to matter: import Tkinter first
import Image, ImageTk # then import ImageTk
class MyFrame(Frame):
def __init__(self, master, im):
Frame.__init__(self, master)
self.caption = Label(self, text="Some text about the map")
self.caption.grid()
self.image = ImageTk.PhotoImage(im) # <--- results of PhotoImage() must be stored
self.image_label = Label(self, image=self.image, bd=0) # <--- will not work if 'image = ImageTk.PhotoImage(im)'
self.image_label.grid()
self.grid()
im = Image.open("test.html") # read map from disk
# or you could use the PIL image you created directly via option 2 from the URL request ...
mainw = Tk()
mainw.frame = MyFrame(mainw, im)
mainw.mainloop()
And with that Window Frame I want to display the 'htm' image of the Google Map in that Window Frame.
The htm image pymaps produces isn't an image, it's an html file. Basically a little webpage. To display it, you would have to render the html. The only html renderer for TkInter that I know of is TkHTML, although I've never used it, so it might not support all the javascript that you html file uses.
You would be much better off dropping TkInter entirely and switching to a more modern widget toolkit such as wxPython which has html rendering built in. You can see the documentation for html in wxPython here. If you have GTK on your system, I've used pywebkitgtk successfully.
However, do you need to render this frame for something specific? If you just want to open the file from python, you can use the webbrowser built in library to open it with your default browser.
import webbrowser
webbrowser.open('test.htm')
And that's it.
If somebody wants to have an interactive Google-Maps widget inside their Tkinter application like in the example above, I wrote a small library that displays tile based maps. The standard server is OpenStreetMap but you can change it to Google-Maps if you want. But note that the Google-Maps tile server is deprecated and will probably don't work at some point in the future.
Documentation: https://github.com/TomSchimansky/TkinterMapView
Install: pip3 install tkintermapview
With the following code you get a fully working Google-Maps widget inside a Tkinter window:
import tkinter
from tkintermapview import TkinterMapView
root_tk = tkinter.Tk()
root_tk.geometry(f"{600}x{400}")
root_tk.title("map_view_simple_example.py")
# create map widget
map_widget = TkinterMapView(root_tk, width=600, height=400, corner_radius=0)
map_widget.pack(fill="both", expand=True)
# google normal tile server
self.map_widget.set_tile_server("https://mt0.google.com/vt/lyrs=m&hl=en&x={x}&y={y}&z={z}&s=Ga", max_zoom=22)
map_widget.set_address("Berlin Germany", marker=True)
root_tk.mainloop()

Creating Blank Images in Python (allowing pixel by pixel manipulation)

I have this code here that creates a Tkinter Canvas widget, then embeds an image within it.
import Tkinter
from PIL import ImageTk, Image
class image_manip(Tkinter.Tk):
def __init__(self):
Tkinter.Tk.__init__(self)
self.configure(bg='red')
self.ImbImage = Tkinter.Canvas(self, highlightthickness=0, bd=0, bg='blue')
self.ImbImage.pack()
self.i = ImageTk.PhotoImage(Image.open(r'test.png'))
self.ImbImage.create_image(150, 100, image=self.i)
def run():
image_manip().mainloop()
if __name__ == "__main__":
run()
I'd like to be able to create a blank image within the Canvas widget, so that I could do pixel by pixel manipulation within the widget. How would one go about this?
To create a new blank image (rather than opening one), you can use the Image.new(...) method in place of your Image.open(...). It is described in The Image Module.
Then call self.i.put(...) to do pixel-by-pixel manipulation. (i is the PhotoImage object as in your example.)
Here's some general information on The Tkinter PhotoImage Class.

Categories