0

I am using the below code to create a window and raise different frames around. I need to create a toplevel, but I am trying to make the Toplevel window appear within the bounds of the main window. Looking around on here, I am finding the way to do this is to use wm_transient(root). The problem is my "root" is called app, and its not accessible from within the class where I am calling these functions.

So my popup function I am calling, I am trying to make my popup (toplevel) have the attribute of wm_transient, but I have to set the master to root (app in my application) and cannot figure out how to make this work.

So my underlying question is how to make the toplevel appear within the bounds of my main window, but what I would really like to know is how to make calls/reference my root window.

import tkinter as tk

class APP1(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.title('APP')
        self.geometry("552x700")
        self.resizable(False, False)

        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 = {}

        self.frames["MenuPage"] = MenuPage(parent=container, controller=self)
        self.frames["MenuPage"].grid(row=0, column=0, sticky="nsew")
        self.show_frame("MenuPage")

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

class MenuPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        def popup():
            x = tk.Toplevel(self)
            x.wm_transient(app)

        template = tk.Button(self, text='Popup', height=3, width=20, bg='white', font=('12'), command=lambda: popup())
        template.pack(pady=50)


if __name__ == "__main__":
    app = APP1()
    app.mainloop()
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Lzypenguin
  • 945
  • 1
  • 7
  • 18
  • 1
    How would you solve the problem if tkinter *weren't* involved? `app` is the object in question, right? Where do you want to reference it *from*? Can you think of a way to get the information there? For example, by using the parameters to `__init__` or other methods? – Karl Knechtel Feb 01 '22 at 03:30
  • @KarlKnechtel I honestly do not know how I would even go about accessing it. This is my first project using classes, so this is all new(ish) to me. Beyond understanding that the __init__ method is called when the class is called, I do not really know what else the __init__ method does. I am not asking to be spoon fed the answer, but I really am not sure how to get to where I think your pointing me yet. – Lzypenguin Feb 01 '22 at 03:34
  • 1
    Forget about the current problem and imagine a simpler example. You have a two classes, and an instance of each. You want a method from one of them to make use of the instance of the other. What strategies are available to you? (Hint: *everything you can assign to a variable in Python* is "an instance of a class" - just not necessarily one you wrote yourself. So, how do you solve that problem with, for example, an `int`?). – Karl Knechtel Feb 01 '22 at 03:37
  • 1
    "The problem is my "root" is called app, and its not accessible from within the class where I am calling these functions." Right. So, did you ever encounter a problem like that *without* classes? For example, trying to use two ordinary *functions*? How did you solve it then? – Karl Knechtel Feb 01 '22 at 03:38
  • @KarlKnechtel Before using classes, and I needed to access something, I just added a global tag to it and I was able to access it anywhere from within the app. – Lzypenguin Feb 01 '22 at 03:39
  • 1
    Try to think more clearly about what the code is *already* doing. Where you have `MenuPage(parent=container, controller=self)`, what does that *mean*? Where you have `self.controller = controller`, what value do you think `controller` will have at this point? What will get stored in `self.controller`? Can you think of a way to use that value to solve the problem? – Karl Knechtel Feb 01 '22 at 03:46
  • 1
    (The reason I am being indirect and not posting an answer here, is because the question is too specific and personal to your project to be useful to others. Stack Overflow is not a tutoring service. If you are struggling here, my earnest suggestion is to take a step back and try to learn the fundamentals properly first, before trying to tackle a GUI project with tkinter. Take things a step at a time. There are definitely simpler ways to become acquainted with classes.) – Karl Knechtel Feb 01 '22 at 03:47
  • @KarlKnechtel Honestly, this is way more helpful than just posting the answer because "UNDERSTANDING" the answer is far more valuable than just having the answer. So my main APP1 is my root instance? And when APP1 calls other classes like MenuPage, they create their own instance, self, but always have a reference to root via the controller? – Lzypenguin Feb 01 '22 at 03:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/241600/discussion-between-lzypenguin-and-karl-knechtel). – Lzypenguin Feb 01 '22 at 03:51
  • In your case, your "root" is `app` and it's a global variable. – Bryan Oakley Feb 01 '22 at 04:19
  • @BryanOakley app is global by default? I can call app (the instance of APP1) from anywhere else in my code just using app? – Lzypenguin Feb 01 '22 at 04:22
  • It's global because you've declared it in the global scope (ie: not in a function or class definition). – Bryan Oakley Feb 01 '22 at 04:24

1 Answers1

2

In your specific example you already have two ways to access your "root".

First, your root is app, the instance of APP1, and it's a global variable so it is already available everywhere. It's global because you define it outside the context of a function or class.

Second, you pass the instance of APP1 as the controller parameter in your MenuPage class. You're saving that as self.controller, so anywhere you need the instance of APP1 you can use self.controller.

For more help understanding the code you've copied, see Switch between two frames in tkinter which contains links to many questions that have been asked about this code.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thank you for this answer. It does answer the question I posed, which was how to access the root object. My intent in asking this question was because I was following this guide: https://www.tutorialspoint.com/how-to-put-a-toplevel-window-in-front-of-the-main-window-in-tkinter to attempt to make my Toplevel window appear in the middle of my main root window, but I could not figure out how to reference "root" in my case. The wm_transient function does not act like I expected, which caused confusion on my end. I should have phrase my question differently. – Lzypenguin Feb 01 '22 at 04:33