0

I'm not sure what is wrong with my code but whenever I try to run it I get the following error:

File "L:\Year 12 and 13\Computer Science\NEA\30.11.18\GUI TKINTER\no cont.py", line 80, in __init__
    button3 = tk.Button(self, command=lambda: controller.MusicClick(), image = musicPic, text="Music", fg="Orange",font="none 20").place(x=30, y=640)
  File "C:\Program Files (x86)\Python36-32\lib\tkinter\__init__.py", line 2363, in __init__
    Widget.__init__(self, master, 'button', cnf, kw)
  File "C:\Program Files (x86)\Python36-32\lib\tkinter\__init__.py", line 2293, in __init__
    (widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage1" doesn't exist

I know it must be a problem with the OOP aspect of the code as I have a very similar non-OOP version of this code which works perfectly with no errors:

#Importing GUI
from tkinter import *

#Window Properties
window = Tk()
window.geometry('1280x720')
window.configure(background="blue")

#Declaring
SFXisMuted = False
MusicisMuted = False

#Title
Label (window, text="Connect 4 - Made by Luke Petrocochino", bg="blue", fg="white", font="Comic_Sans 40 bold").place(x=150,y=150)

#Pictures
musicPic = PhotoImage(file="musicalnoteresize.gif")
musicPicMUTED =PhotoImage(file="musicalnoteresizeMUTED.gif")
SFXPic = PhotoImage(file="SFXresize.gif")
SFXPicMUTED = PhotoImage(file="SFXresizeMUTED.gif")

#Command Sub Routines

def SFXClick():
    global SFXisMuted
    if SFXisMuted == False:
        button4 = Button(command=SFXClick, text="SFX", image=SFXPicMUTED, fg="Orange",font="none 20").place(x=110, y=640)
        SFXisMuted = True
    else:
        button4 = Button(command=SFXClick, text="SFX", image=SFXPic, fg="Orange",font="none 20").place(x=110, y=640)
        SFXisMuted = False

def MusicClick():
    global MusicisMuted
    if MusicisMuted == False:
        button3 = Button(command=MusicClick, text="Music",image=musicPicMUTED, fg="Orange",font="none 20").place(x=30, y=640)
        MusicisMuted = True
    else:
        button3 = Button(command=MusicClick, text="Music",image=musicPic, fg="Orange",font="none 20").place(x=30, y=640)
        MusicisMuted = False

def CloseWindow():
    window.destroy()
    exit()

#Buttons
button1 = Button(text ="Play!", font="none 60", fg= "Green").place(x=550, y=280)

button2 = Button(command=CloseWindow, text="Exit ",font="none 20", fg="Red").place(x=1175, y=640)

button3 = Button(command=MusicClick, text="Music",image=musicPic, fg="Orange",font="none 20").place(x=30, y=640)

button4 = Button(command=SFXClick, text="SFX", image=SFXPic, fg="Orange",font="none 20").place(x=110, y=640)



#End
window.mainloop()

This is my version made with OOP which gives me the error: (I have all of my image files in the directory where my code is saved as well.)

#Importing GUI

import tkinter as tk
app = tk.Tk()
LARGE_FONT= ("Verdana", 12)


class Connect4(tk.Tk):

    def __init__(self, *args, **kwargs):

        tk.Tk.__init__(self, *args, **kwargs)        
        container = tk.Frame(self)

        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        SFXisMuted = False
        MusicisMuted = False

        for F in (StartPage, PageOne, PageTwo):

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

    def SFXClick(self):
        global SFXPic
        global SFXisMuted
        if SFXisMuted == False:
            button4 = Button(command=SFXClick, text="SFX", image=SFXPicMUTED, fg="Orange",font="none 20").place(x=110, y=640)
            SFXisMuted = True
        else:
            button4 = Button(command=SFXClick, text="SFX", image=SFXPic, fg="Orange",font="none 20").place(x=110, y=640)
            SFXisMuted = False
        print("it works")

    def MusicClick(self):
        global MusicisMuted
        global musicPic
        if MusicisMuted == False:
            button3 = Button(command=lambda: controller.MusicClick, text="Music",image=musicPicMUTED, fg="Orange",font="none 20").place(x=30, y=640)
            MusicisMuted = True
        else:
            button3 = Button(command=MusicClick, text="Music",image=musicPic, fg="Orange",font="none 20").place(x=30, y=640)
            MusicisMuted = False

    def CloseWindow(self):
        Connect4.destroy(self)
        exit()

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Start Page", font=LARGE_FONT)
        musicPic = tk.PhotoImage(file="musicalnoteresize.gif")
        SFXPic = tk.PhotoImage(file="SFXresize.gif")

        label = tk.Label(self, text="Connect 4 - Made by Luke Petrocochino", bg="blue", fg="white", font="Comic_Sans 40 bold").place(x=150,y=150)

        button1 = tk.Button(text ="Play!", font="none 60", fg= "Green").place(x=550, y=280)

        button2 = tk.Button(self, command=lambda: controller.CloseWindow(),  text="Exit ",font="none 20", fg="Red").place(x=1175, y=640)

        button3 = tk.Button(self, command=lambda: controller.MusicClick(), image = musicPic, text="Music", fg="Orange",font="none 20").place(x=30, y=640)

        button4 = tk.Button(self, command=lambda: controller.SFXClick(), image = SFXPic, text="SFX", fg="Orange",font="none 20").place(x=110, y=640)

        button3.image = musicPic
        button4.image = SFXPic

class PageOne(tk.Frame):

def __init__(self, parent, controller):
    tk.Frame.__init__(self, parent)
    label = tk.Label(self, text="Page One", font=LARGE_FONT)
    label.pack(pady=10,padx=10)

    buttonNav = tk.Button(self, text="Back to Home",
                          command=lambda: controller.show_frame(StartPage))
    buttonNav.pack()


class PageTwo(tk.Frame):

def __init__(self, parent, controller):
    tk.Frame.__init__(self, parent)
    label = tk.Label(self, text="Page Two", font=LARGE_FONT)
    label.pack(pady=10,padx=10)

    buttonNav = tk.Button(self, text="Back to Home",
                          command=lambda: controller.show_frame(StartPage))
    buttonNav.pack()

    button2 = tk.Button(self, text="Page One",
                          command=lambda: controller.show_frame(PageOne))
    button2.pack()



app = Connect4()
app.geometry('1280x720')
app.configure(background="blue")
app.mainloop()

I am new to tkinter an OOP so my apologies if it is a very simple error.

j_4321
  • 15,431
  • 3
  • 34
  • 61

1 Answers1

0

This was difficult to find. You are making a common error when creating the buttons by passing them to place(). Place will return None which means you will have no reference to the buttons.

button3 = tk.Button(self, command=lambda: controller.MusicClick(),
                    image = musicPic, text="Music",
                    fg="Orange", font="none 20").place(x=30, y=640)

Instead create the button first and place it after:

button3 = tk.Button(self, command=lambda: controller.MusicClick(),
                    image = musicPic, text="Music",
                    fg="Orange", font="none 20")
button3.place(x=30, y=640)

Otherwise you will not be able to save the image to the button:

button3.image = musicPic

Then you also made an unusual error in that you create the root window:

app = tk.Tk()

and name your application as the same name:

app = Connect4()

This has an effect but I don't understand exactly why this is, but the effect is that the button can not find the image you are passing to it. If you just delete the first app = tk.Tk() it all works ok.

Also; in the function MusicClick() in Connect4 you are making a couple of variables global. This seems strange to me as one of the benifits of OOP is that you don't need globals. I would make them instance variables instead.

figbeam
  • 7,001
  • 2
  • 12
  • 18
  • While you are correct that `place` returns `None`, that's not the problem. The stack trace happens with the creation of the button rather then when trying to access it later. – Bryan Oakley Dec 07 '18 at 22:39
  • I don't understand what that means. Can you provide a link to a more thorough explanation or description of how this works. – figbeam Dec 08 '18 at 05:39
  • I don't know how else to explain it. The problem is with the creation of the widget, not with trying to modify it later. In other words, the error happens _before_ `.place` is called. – Bryan Oakley Dec 08 '18 at 06:00
  • Yes, I agree. But I am confused as to the exact problem; is it multiple instances of `Tk()` that screwes up the button creation? – figbeam Dec 08 '18 at 06:40
  • Thank you the program now runs. However I am still having problems with my functions. You say I do not need the global variables and should make them instance variables instead. So where should I declare these variables and would I have to pass them through the parentheses when calling the function? – Luke Petrocochino Dec 12 '18 at 09:26
  • You can declare instance variables anywhere in a class and they will be accessible from any function in that class whthout passing them through the parenthesis. Sort of global but only to one instance of the class. Here is a [good overview](https://www.tutorialspoint.com/python/python_classes_objects.htm) which explains the basic concepts and names. – figbeam Dec 12 '18 at 11:30