Search code examples
pythonpython-3.xtkinterframetkinter-layout

Click on a button and open the content in a frame (direct way in frame and way with import script .py)


I would like to click a button and view its content on the rest of the screen (where the gray color is), but through the frame, not across the canvas.

I would need 2 examples, but apply to my code please:

  • example 1: click on button 1 and color the page (as in the classic use in these frames) with the code written in the same single file
  • example 2: click on the button and import an external py file as a module, then the contents of the external file will open completely inside the gray screen

I would need these two simple examples, because for each frame (therefore for each button) I will have a long enough code and I would like to manage it in an orderly and clean way. So I would like to test both examples, but applied to my code.

I've seen examples on the web and on StackOverflow before, but I couldn't apply myself to my code. Can you please help me use my code?

(my code below)

enter image description here

from tkinter import messagebox
import tkinter as tk
from tkinter import ttk
from PIL import ImageTk, Image

root = tk.Tk()
root.title("xxxx")
root.geometry("1920x1080+0+0")
root.config(bg="#f0f0f0")
root.state("normal")

topbar = tk.Frame(root, background="#e10a0a", height=43)
topbar.pack(fill='x') # use pack() instead of place()

leftbar = tk.Frame(root, width=250, background="white")
leftbar.pack(side='left', fill='y') # use pack() instead of place()
leftbar.pack_propagate(0) # disable size auto-adjustment

def clicked(btn):
    for w in leftbar.winfo_children():
        w['bg'] = 'white' if w is not btn else 'yellow'

button1 = tk.PhotoImage(file="/image.png")
btn1 = tk.Button(leftbar, image=button1, borderwidth=0, highlightthickness=0,
                 bg="white", text="aaaaa", foreground='green', compound='left', anchor='w')
btn1.pack(fill='x') # use pack() instead of place()
btn1['command'] = lambda: clicked(btn1)

button2 = tk.PhotoImage(file="/image.png")
btn2 = tk.Button(leftbar, image=button2, borderwidth=0, highlightthickness=0,
                 bg="white", text="bbbbb", foreground='green', compound='left', anchor='w')
btn2.pack(fill='x') # use pack() instead of place()
btn2['command'] = lambda: clicked(btn2)

root.mainloop()

Solution

  • You can use a ttk.Notebook to achieve what you want:

    import tkinter as tk
    from tkinter import ttk
    from PIL import ImageTk
    
    # define classes for each page
    
    class Page1(tk.Frame):
        def __init__(self, master, **kw):
            super().__init__(master, **kw)
            tk.Label(self, text='Hello', font='Arial 64 bold').pack(fill='both', expand=1)
    
    class Page2(tk.Frame):
        def __init__(self, master, **kw):
            super().__init__(master, **kw)
            tk.Label(self, text='Python is awesome', font='Times 24 bold', bg=self['bg']).pack()
            self.logo = ImageTk.PhotoImage(file='images/python-logo.png')
            tk.Label(self, image=self.logo, bg=self['bg']).pack(fill='both', expand=1)
    
    root = tk.Tk()
    root.geometry('640x480')
    
    topbar = tk.Frame(root, bg='#e10a0a', height=43)
    topbar.pack(fill='x')
    
    style = ttk.Style()
    style.theme_use('default') # select a theme that allows configuration of ttk.Notebook
    # put the tabs at the left with white background
    style.configure('TNotebook', tabposition='wn', background='white', tabmargins=0)
    # configure tab with white background initially, yellow background when selected
    style.configure('TNotebook.Tab', background='white', width=10, focuscolor='yellow', borderwidth=0)
    style.map('TNotebook.Tab', background=[('selected', 'yellow')])
    
    nb = ttk.Notebook(root)
    nb.pack(fill='both', expand=1)
    
    img = ImageTk.PhotoImage(file='images/div2.png')
    
    page1 = Page1(nb)
    page2 = Page2(nb, bg='pink', bd=0)
    
    nb.add(page1, text='aaaaa', image=img, compound='left')
    nb.add(page2, text='bbbbb', image=img, compound='left')
    
    root.mainloop()
    

    Output:

    enter image description here


    You can also put the class definitions of each page to external files, for example Page1 in page1.py and Page2 in page2.py. Then import them into main script:

    import tkinter as tk
    from tkinter import ttk
    from PIL import ImageTk
    from page1 import Page1
    from page2 import Page2
    
    root = tk.Tk()
    root.geometry('640x480')
    
    topbar = tk.Frame(root, bg='#e10a0a', height=43)
    topbar.pack(fill='x')
    
    style = ttk.Style()
    style.theme_use('default') # select a theme that allows configuration of ttk.Notebook
    # put the tabs at the left with white background
    style.configure('TNotebook', tabposition='wn', background='white', tabmargins=0)
    # configure tab with white background initially, yellow background when selected
    style.configure('TNotebook.Tab', background='white', width=10, focuscolor='yellow', borderwidth=0)
    style.map('TNotebook.Tab', background=[('selected', 'yellow')])
    
    nb = ttk.Notebook(root)
    nb.pack(fill='both', expand=1)
    
    img = ImageTk.PhotoImage(file='images/div2.png')
    
    page1 = Page1(nb)
    page2 = Page2(nb, bg='pink', bd=0)
    
    nb.add(page1, text='aaaaa', image=img, compound='left')
    nb.add(page2, text='bbbbb', image=img, compound='left')
    
    root.mainloop()
    

    page1.py

    import tkinter as tk
    
    class Page1(tk.Frame):
        def __init__(self, master, **kw):
            super().__init__(master, **kw)
            tk.Label(self, text='Hello', font='Arial 64 bold').pack(fill='both', expand=1)
    

    page2.py

    import tkinter as tk
    from PIL import ImageTk
    
    class Page2(tk.Frame):
        def __init__(self, master, **kw):
            super().__init__(master, **kw)
            tk.Label(self, text='Python is awesome', font='Times 24 bold', bg=self['bg']).pack()
            self.logo = ImageTk.PhotoImage(file='images/python-logo.png')
            tk.Label(self, image=self.logo, bg=self['bg']).pack(fill='both', expand=1)