tony
tony

Reputation: 19

unable to eliminate a global variable

I have a fairly lengthy GUI image viewing program, the "globals" started to get out of hand and I have eliminated them all but one. The simplified code below shows the global variable art. with it in place the image is displayed, without it - a grey screen. I would appreciate any help in understanding what is going on

from tkinter import *
from PIL import ImageTk,Image

root = Tk()

def image():
    global art
    path="c:/Google Drive/Art Images/0030#Van Tromp, going about to please his Masters.jpg"
    image=Image.open(path)
    art = ImageTk.PhotoImage(image)
    label.grid()
    label.configure(image=art)

label=Label(root,bg="grey")
image()

root.mainloop()

Upvotes: 0

Views: 134

Answers (2)

Andereoo
Andereoo

Reputation: 958

Your issue is that when creating a Photoimage, you need to keep a reference to that image, meaning you need to assign that image a variable name that can be accessed elsewhere. In your case, the variable art, without using a global, stays in the function. This means that when the function finished, art is destroyed. An easy fix is to return the variable art, making the output of the function art, and thus bringing the variable into the main code. This is what effbot has to say about that:

When you add a PhotoImage or other Image object to a Tkinter widget, you must keep your own reference to the image object. If you don’t, the image won’t always show up.

The problem is that the Tkinter/Tk interface doesn’t handle references to Image objects properly; the Tk widget will hold a reference to the internal object, but Tkinter does not. When Python’s garbage collector discards the Tkinter object, Tkinter tells Tk to release the image. But since the image is in use by a widget, Tk doesn’t destroy it. Not completely. It just blanks the image, making it completely transparent

To fix this, you could use a global variable (which can be accessed elsewhere in the main code, thus becoming a 'reference'), or you could do something like this:

from tkinter import *
from PIL import ImageTk,Image

root = Tk()

def image():
    label.grid()
    path="c:/Google Drive/Art Images/0030#Van Tromp, going about to please his Masters.jpg"
    image=Image.open(path)
    art = ImageTk.PhotoImage(image)
    label.configure(image=art)
    return art

label=Label(root,bg="grey")
image()


root.mainloop()

In that code, your image is returned by the function and assigned a variable in the main code, making is a 'reference' without globals.

You can find more info here

Upvotes: 1

Kyle Alm
Kyle Alm

Reputation: 587

Your function, image(), is being used to output your image, and to do that, you're assigning it to the variable 'art'. An image object is created, but when your function ends, since you aren't returning anything, that object ceases to exist:

y = 5

def getx():
  x = 3

getx()
a = y + x

This code won't work, because x is local to the function getx(). Since I'm not doing anything with it, when the function ends, so does the variable. What I can do, though, is pass data out of the function, like this:

y = 5

def getx():
  x = 3
  return x

x = getx()
a = y + x

In your code, tkinter needs for the image object to exist when it runs, but while you created it within your function, you let the function end without doing anything with it. Naming art a global variable effectively allows your function to return your object to a variable outside of the function. Another way to do it, though would be:

root = Tk()

def image():
  path="c:/Google Drive/Art Images/0030#Van Tromp, going about Masters.jpg"
  image=Image.open(path)
  art = ImageTk.PhotoImage(image)
  label.grid()
  label.configure(image=art)
  return art

label=Label(root,bg="grey")
art = image()

root.mainloop()

Upvotes: 0

Related Questions