0

I wrote my first Tkinter app that contains a button which, on clicking, is supposed to display an image in a canvas:

import tkinter as tk
from PIL import Image, ImageTk
import numpy as np
from itertools import cycle

import helpers


class App():

    def __init__(self, master):
        frame = tk.Frame(master)
        frame.pack()

        self.canvas = tk.Canvas(width=500, height=500)
        self.canvas.pack()

        self.load_button = tk.Button(
            frame, text="Load image", command=self.load_image)
        self.load_button.pack(side=tk.LEFT)
        self.img_no = 0

    def load_image(self):
        stack = helpers.read_image_sequence("path")
        data = stack[self.img_no]
        im = Image.fromarray(data)
        im = im.resize((200, 200))
        photo = ImageTk.PhotoImage(image=im)
        self.canvas.create_image(0, 0, image=photo, anchor=tk.NW)
        self.pack()


root = tk.Tk()

app = App(root)

root.mainloop()

After clicking the button, the image won't appear unless I add self.pack() at the end of its function. This works but causes the error:

AttributeError: 'App' object has no attribute 'pack'

Apparently this is because my App() class doesn't inherit from a suitable parent. How to do this properly? I tried tk.Tk as parent:

class App(tk.Tk):

def __init__(self, master):
    super().__init__()

Which results in the error:

AttributeError: '_tkinter.tkapp' object has no attribute 'pack'

And I tried tk.Frame which doesn't result in any error, but the image doesn't show either! What am I missing..? Using Python 3.5.

nandal
  • 2,544
  • 1
  • 18
  • 23
smcs
  • 1,772
  • 3
  • 18
  • 48
  • sure u need specify what u want back, self refer only to instance attribute but self without anything is not referring to any elements; if you notice before you did self.canvas.pack() and worked without problems – Carlo 1585 Jun 29 '18 at 08:59
  • 2
    Why do you think you need `self.pack()`? You've packed all widgets and you class is not a widget, so you don't need to (and can't) pack it. The reason you're not seeing the image is because it is garbage collected. Change `photo` to `self.photo` and you should be good. More info [here](https://stackoverflow.com/questions/16424091/why-does-tkinter-image-not-show-up-if-created-in-a-function/16424553#16424553) and [here](http://effbot.org/pyfaq/why-do-my-tkinter-images-not-appear.htm). – fhdrsdg Jun 29 '18 at 11:24
  • @fhdrsdg Thanks, that did it! It's quite simple, intuitively I thought I needed to `pack` the GUI to update it, as I've seen before in other frameworks in similar ways. And using `self.pack()` did work, the image showed up! It's probably though because the exception it caused hindered garbage collection... – smcs Jun 29 '18 at 11:39
  • 1
    `It's probably though because the exception it caused hindered garbage collection` Exactly, the exception was raised before the function returned! When you see `pack` called on a class, it's usually a class that inherits from `tk.Frame`. If you do that, you can use `self` as the master of all widgets and `pack` the frame in your `Tk` instance either from inside or outside the class. – fhdrsdg Jun 29 '18 at 12:22
  • 1
    By the way, when you call `self.canvas = tk.Canvas(width=500, height=500)`, the canvas is placed in `root`, not in your `frame`, because you didn't specify the master. That's why your button is put above your canvas now. – fhdrsdg Jun 29 '18 at 12:23

0 Answers0