-1

I am wanting to create a tkinter window where when I click a button widget it opens a new window, showing all the widgets, exactly the same, from the root/original window. Essentially creating a second instance of the root window, where the application can have multiple users, using the same GUI, in different windows.

Any help is appreciated.

An example of one of my widgets:

    summary_output = Text(
                    master=window, 
                    height=8,
                    width=78,
                    bg="gray95",
                    borderwidth=2, 
                    relief="groove",
                    font=("Arial", 12))

My window layout

    window = Tk()
    window.title("Data Viewer")
    window.geometry("750x950")
    window.configure(bg='white')
    window.iconphoto(False, tk.PhotoImage(file='icon.png'))

I have this but cant seem to place the widgets from the root window:


    def new_window():
        newWindow = Toplevel(window)
        newWindow.geometry("750x950")
        newWindow.configure(bg='white')
        newWindow.iconphoto(False, tk.PhotoImage(file='icon.png'))
        upload_button.place(x=20, y=560)
        mainloop()

Is their anyway to change the master to be any window?

Edit:

from tkinter import *

class StaticFrame(Frame):
    def __init__(self,master,*args,**kwargs):
        Frame.__init__(self,master,*args,**kwargs)

        # All your widgets
        Label(self,text='This is a reusable frame',font=(0,17)).place(x=0, y=0)
        Button(self,text='Click me for nothing').pack()
        Label(self,text='End of page').pack()
        upload_button = Button(
                self, 
                text="Edit Data",
                fg="DodgerBlue4",
                font=("Graph Type", 15),
                height=1, width=12,
                borderwidth=2,
                relief="groove")
        upload_button.place(x=20, y=50)

root = Tk() # First window
top  = Toplevel(root) # Second window
root.geometry("750x968")
StaticFrame(root).pack() # Put the frame on the first window
StaticFrame(top).pack() # Put the frame on the second window

root.mainloop()

Result:

enter image description here

Travis B
  • 57
  • 1
  • 8
  • Please see [this](https://meta.stackoverflow.com/q/334822) for information on homework questions. Also, questions must show a research effort; currently, your question does not show any research effort. There is plenty of information on Stack Overflow and online on how to create and use classes. – Sylvester Kruin Sep 26 '21 at 20:56
  • 1
    Yes, but your question is very broad, and already has answers. You want to make a window that there can be multiple identical instances of, but with different contents for different users, correct? [Here](https://stackoverflow.com/questions/30489308/creating-a-custom-widget-in-tkinter?r=SearchResults&s=3|73.8528) [are](https://stackoverflow.com/questions/11892521/tkinter-custom-window) [some](https://stackoverflow.com/questions/18608377/python-tkinter-custom-window) [related](https://stackoverflow.com/questions/11179642/python-tkinter-make-a-custom-window) questions on custom tkinter widgets. – Sylvester Kruin Sep 26 '21 at 21:13
  • I'm sure there are plenty of tutorials online that you could use, as well. Do some research, and be creative. If you have a specific error with some specific code, we'll be happy to help. You can also search `[python] class inheritance` on SO for more information on classes and creating custom inherited classes, but the questions I gave you links to should be a start. – Sylvester Kruin Sep 26 '21 at 21:17
  • @SamMatzko if it already has answers why cant I find them?? – Travis B Sep 26 '21 at 21:21
  • @TravisB: It seems your approach is to move the widgets themselves into a new window, which is not possible in tkinter anyway. `upload_button` has one, and only one, master, and that is `window` (not `newWindow`); calling `upload_button.place()` only puts it in `window` over again. The links I provided are about another solution: using classes and inheritance to create a custom window class, with its own widgets. You could then create instances of your custom window, in much the same way as you create instances of `tkinter.Tk()`. Yours could have any data-storage you wanted them to. – Sylvester Kruin Sep 26 '21 at 21:30
  • @SamMatzko how do I do that? – Travis B Sep 26 '21 at 21:41
  • @TravisB [Here](https://stackoverflow.com/questions/42329556/add-custom-attributes-to-a-tk-widget) is a simple example of someone creating a custom Button. Notice that they can specify their own arguments, as well as their own variables (like `self.master` and `self.tag`), in their custom Button class. The same goes for creating any custom tkinter widget. Just search stuff like `[python] [tkinter] custom Tk` or `[python] [tkinter] inheritance` on Stack Overflow. If you have any specific problems or errors along the way, just ask, and we'll be happy to help! – Sylvester Kruin Sep 26 '21 at 21:50
  • It's not clear what you're asking. It sounds like the obvious answer is just to move your code to a function or class, and call that function or instantiate that class as many times as you want. – Bryan Oakley Sep 26 '21 at 21:54
  • Please provide enough code so others can better understand or reproduce the problem. – Community Oct 04 '21 at 14:06

1 Answers1

2

The concept used here is simple, create a "custom frame" that we will put onto these new windows, so that it will create the exact same frame, and widgets within it, inside different windows.

from tkinter import *

class StaticFrame(Frame):
    def __init__(self,master,*args,**kwargs):
        Frame.__init__(self,master,*args,**kwargs)

        # All your widgets
        Label(self,text='This is a reusable frame',font=(0,17)).pack()
        Button(self,text='Click me for nothing').pack()
        Label(self,text='End of page').pack()

root = Tk() # First window
top  = Toplevel(root) # Second window

StaticFrame(root).pack() # Put the frame on the first window
StaticFrame(top).pack() # Put the frame on the second window

root.mainloop()

Very simple to code and has been explained with comments, if you do not know what classes and inheritance is then first do go through those. There are variety of other methods that come onto mind when I read this question, like even having an option database and storing the widgets in a list and recreating it based on its order, but this seems to be the easiest in a scratch.

Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
  • The buttons only work for the 'master'/ first screen. How do I get around this? Many thanks – Travis B Sep 27 '21 at 03:05
  • @TravisB `master` is any screen that you pass as the main widget, anyway it should have been `self`, have updated the answer – Delrius Euphoria Sep 27 '21 at 10:12
  • when I do place it doesnt work please see edit. – Travis B Sep 28 '21 at 01:31
  • @TravisB Your first window is bigger than your 2nd window, because you are using `root.geometry("750x968")`, what else did you expect to happen? – Delrius Euphoria Sep 28 '21 at 14:12
  • No, the label element I added is not visible on both frames at all, please read code again. The size of the frame is not my problem. I also have a problem when I use buttons. Only one set works on the last frame that is created, the second set of buttons dont work. – Travis B Sep 29 '21 at 01:06
  • @TravisB The 2nd button is not showing BECAUSE you are using `place` and the coordinates are outside the dimensions of the frame, use `pack` or make the frame bigger(not so easy), not the window. Better to use `upload_button.pack()`. So actually, the size of the frame is EXACTLY your problem. – Delrius Euphoria Sep 29 '21 at 05:18
  • Its a terrible method as then how do you parse through data when you cannot get the instance? – Travis B Sep 30 '21 at 04:12
  • @TravisB The instance is right there, no problem. In the example there might not be any instance, but if you want to, you can just keep it. No biggie. – Delrius Euphoria Sep 30 '21 at 09:34
  • @TravisB Would appreciate marking as the correct answer, if it answered your questions :D – Delrius Euphoria Oct 02 '21 at 10:40