0

Code Background: trying to have a popup window call a function in another class.

I am having trouble defining controller and configuring my functions correctly. I get an error about controller not being defined before it passes to the popupWindow class which makes sense because I have not defined controller somewhere else but I don't know where to do that:

NameError: name 'controller' is not defined

I have studied these past answers for help but am still stuck:

Calling Tkinter frame controller from function rather then button command

Calling functions from a Tkinter Frame to another

Here is my simplified code (Note: I define the various variables in the values function in other functions within the class BoundingBox but I have not included those functions for clarity and to shorten the code):

I also don't understand how to make the get_page function work which is part of my problem with figuring out how and where to define controller.

import tkinter as tk
from tkinter import *

class BoundingBox(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

    def get_page(self, page_class):
        return self.frames[page_class]

    def popup(self):
        self.w=popupWindow(self.master,controller)

    def values(self):     
        print(self.start_x, self.start_y, self.end_x, self.end_y, self.totwidth, self.totheight, self.value1, self.value2)
        self.allcord.append([self.start_x, self.start_y, self.end_x, self.end_y, self.totwidth, self.totheight, self.value1, self.value2])
        self.allrect.append(self.rect)
        print (len(self.allcord))     

class popupWindow(tk.Toplevel):
    def __init__(self, master, controller):
        super().__init__(master)
        self.controller = controller
        self.l1=Label(self,text="Breed")
        self.l1.grid(row=0, column=0)
        self.e1=Entry(self)
        self.e1.grid(row=0, column=1)
        self.l2=Label(self,text="Color")
        self.l2.grid(row=1, column=0)
        self.e2=Entry(self)
        self.e2.grid(row=1, column=1)
        self.b=Button(self,text='Save',command=self.cleanup)
        self.b.grid(row=2, column=1)

    def cleanup(self):
        self.value1=self.e1.get()
        self.value2=self.e2.get()
        self.controller.values()
        self.top.destroy()

if __name__ == "__main__":
    draw = BoundingBox()
    draw.mainloop()


  • 1
    Your `BoundingBox` class does not have a controller defined anywhere. So the `popup` function does not know it from class scope. Define it somewhere in the init. – Dschoni Mar 09 '20 at 13:29
  • See this answer for a minimal working example: https://stackoverflow.com/questions/7546050/switch-between-two-frames-in-tkinter/7557028#7557028 – Dschoni Mar 09 '20 at 13:30
  • You can do: `class PopupWindow(tk.Toplevel):` and use `self` instead of `top`. – stovfl Mar 09 '20 at 14:10
  • @Dschoni what is the best way to define controller in the BoundingBox init? Would it be something like `controller=None`? – thegreatyonini Mar 09 '20 at 14:42
  • @stovfl could you clarify? So class `PopupWindow(tk.Toplevel):` then `self=self.Toplevel(master)`? How does this relate to controller? – thegreatyonini Mar 09 '20 at 14:45
  • ***"How does this relate to controller? "***: It's unrelated. Don't use `self=self.Toplevel(master)` in general, you never have to assign anything to `self=`. Think of `class PopupWindow` **IS THE** `tk.Toplevel`! – stovfl Mar 09 '20 at 14:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/209322/discussion-between-thegreatyonini-and-stovfl). – thegreatyonini Mar 09 '20 at 15:57

1 Answers1

0

In this specific case, controller simply refers to the main window. So, you simply need to pass self as the controller argument:

def popup(self):
    self.w=popupWindow(self.master, self)

Notice how the cleanup method calls self.controller.values(). values is defined in BoundingBox, so it's clear that popupwindow was designed to have BoundingBox as the controller.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Hi @Bryan, thank you for your clear answer, I am going to try it out now. My references to `top` were a holdover that I forgot to change after @stovfl helped be modify my original init to be `super().__init__(master)`. – thegreatyonini Mar 09 '20 at 16:47