switch frame with tkinter - python-3.x

I use following code:
Switch between two frames in tkinter
import RPi.GPIO as GPIO
from threading import Timer,Thread,Event
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
#import Tkinter as tk # python 2
#import tkFont as tkfont # python 2
#----------------------------------------------------------
#Setup GPIO
#----------------------------------------------------------
GPIO.setwarnings(False)
# RPi.GPIO Layout verwenden (wie Pin-Nummern)
#GPIO.setmode(GPIO.BOARD)
GPIO.setmode(GPIO.BCM)
# (GPIO 17,27,22,5) auf Input setzen
chan_list1 = [17, 27, 22, 5]
GPIO.setup(chan_list1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# (GPIO 12,13,23,24) auf Output setzen
chan_list = [12, 13, 23, 24]
GPIO.setup(chan_list, GPIO.OUT)
#----------------------------------------------------------
#--------------------------------------------------------
#Timer
#--------------------------------------------------------
class perpetualTimer():
def __init__(self,t,hFunction):
self.t=t
self.hFunction = hFunction
self.thread = Timer(self.t,self.handle_function)
def handle_function(self):
self.hFunction()
self.thread = Timer(self.t,self.handle_function)
self.thread.start()
def start(self):
self.thread.start()
def cancel(self):
self.thread.cancel()
#--------------------------------------------------------
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.overrideredirect(1) #Remove Title bar
self.geometry("480x272") #Set the window dimensions
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
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 = {}
for F in (StartPage, PageOne, PageTwo):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
def printer():
print ('PIT(!)')
SampleApp.show_frame('PageOne')
if __name__ == "__main__":
t = perpetualTimer(0.01,printer)
t.start()
app = SampleApp()
app.mainloop()
Is it possible to switch the frames without using buttons?
e.g. comparing a counter. if the counter value is 1 show page 1
if counter value is 2 show page 2 and so on.
If I'm honest, I do not remember exactly what I've all tried.
One thing I tried was "controller.show_frame("StartPage")" from def printer sub.
What I want to achieve is to switch the pages from the "def printer" sub,
which is called periodically.
I do not know if that's possible?

One thing I tried was controller.show_frame("StartPage") from def printer sub.
You have to call switch_frame on the object that has that method. This is no different than any other object or any other class in python.
In your case, since SampleApp is the class that has the method, and app is a global variable that holds an instance of the class, you would do it this way:
app.show_frame("StartPage")

Related

Trouble Binding a Button in a Class - Python (Tkinter)

Just started learning Tkinter and was hoping someone could help me. I've been trying to bind a keyboard character (Enter button) to a tk button following this example and not getting anywhere.
Say I take the button (Enter) and try bind it nothing happens:
Enter.bind('<Return>', lambda:self.retrieve_Input(t))
If I bind to self instead using Lambda nothing happens also. I can get it to trigger if I remove the lambda but that's not the desired outcome
self.bind('<Return>', lambda:self.retrieve_Input(t))
My Code:
import sys
import tkinter as tk
from tkinter import ttk
class windows(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("Test Application")
self.lift() #Bringing the GUI to the front of the screen
main_frame = tk.Frame(self, height=400, width=600) #Creating a main Frame for all pages
main_frame.pack(side="top", fill="both", expand=True)
main_frame.grid_rowconfigure(0, weight=1) #Configuring the location of the main frame using grid
main_frame.grid_columnconfigure(0, weight=1)
# We will now create a dictionary of frames
self.frames = {}
for F in (MainPage, CompletionScreen): #Add the page components to the dictionary.
page = F(main_frame, self)
self.frames[F] = page #The windows class acts as the root window for the frames.
page.grid(row=0, column=0, sticky="nsew")
self.show_page(MainPage) #Method to switch Pages
def show_page(self, cont):
frame = self.frames[cont]
frame.tkraise()
##########################################################################
class MainPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#switch_window_button = tk.Button(self, text="Go to the Side Page", command=lambda: controller.show_page(SidePage))
#switch_window_button.pack(side="bottom", fill=tk.X)
tk.Label(self, text="Project Python Search Engine", bg='white').pack()
tk.Label(self, text="", bg='white').pack()
tk.Label(self, text="Song", bg='white').pack()
tk.Label(self, text="", bg='white').pack()
t = tk.Entry(self, bg='white', width = 50)
t.pack()
tk.Label(self, text="", bg='white').pack()
Enter = tk.Button(self, text='Search', command= lambda:self.retrieve_Input(t))
Enter.pack()
tk.Button(self, text="Latest Popular Songs", command=lambda:self.Popular_Songs(t)).pack() #Line 210 onwards
Enter.bind('<Return>', lambda:self.retrieve_Input(t))
def retrieve_Input(self, t):
print ("work")
print (t)
class CompletionScreen(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Completion Screen, we did it!")
label.pack(padx=10, pady=10)
switch_window_button = ttk.Button(
self, text="Return to menu", command=lambda: controller.show_page(MainPage)
)
switch_window_button.pack(side="bottom", fill=tk.X)
if __name__ == "__main__":
App = windows()
App.mainloop()
I'm not really sure what I'm missing
Answer: The button probably doesn't have the keyboard focus. When I run your code and then use the keyboard to move the focus to the button, your binding works. You probably want to bind to the entry widget rather than the button since that's what will have the keyboard focus. – Thanks Bryan Oakley

Python Tkinter: How reset a combobox label from selecting option in another combobox in a parent, controler, container model?

The code is correct (and very interesting indeed - From stackoverlflow, because facilitate working comboboxes in classes!). The code is a little long, but just to create the structure to make combobox work in this parent, controler, container model. On the other hand,comoboboxes are "burning my brains out". The hard part: I can reset the lower combobox clicking the button. But I need to reset it to 'I´m your friend' just choosing any option in upper combobox (without use of button). I've tried insert "self.combobox_HPFilter.set('I´m your friend')" in a function and insert this in the functions called "make_guess", unfortunately unsuccessfuly. I really appreciate any help.
# from Bryan Oakley and others from the "amazing" Stackoverflow
# https://stackoverflow.com/questions/7546050/switch-between-two-frames-in-tkinter/7557028#7557028
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
from tkinter import ttk
class SampleApp(tk.Tk):
'''
All the code is working.The sole issue is: to reset second combobox text direct from options in upper combobox
'''
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
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 = {}
for F in (StartPage, PageOne):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def make_guess01(self):
print("I've got a cute friend")
def make_guess02(self):
print('Ned is correct')
def make_guess03(self):
print('Patrick')
def make_guess04(self):
print('Best Hommer friend')
def labels_reset(self):
self.combobox_HPFilter.set('I´m your friend')
#-------------------------first combobox start
def change_Montage_combobox(self, event): # this method goes inside def montage_Combo(self):
myvar = (self.comboboxMontages.get())
# lines 1 2 3 4 say that values(function_name) in montageDict are functions in StartPage
function_name = self.montagesDict[myvar] #1 returns the function(method) in montageDic(value of key:value pair)
# just for reference: print(function_name)--> montage_Original (dictionary montagesDict value)
an_object = StartPage(self, tk.Frame) # 2--> the page (class) where function is
class_method = getattr(StartPage, function_name) # 3 returns method and says the page of the method
result = class_method(an_object) # 4 result is the method right for use
def montage_Combo(self):
self.montage_selector = tk.StringVar()
self.comboboxMontages = ttk.Combobox(self, values=sorted(list(self.montagesDict.keys())),
justify="center", textvariable=self.montage_selector, state="readonly",
)
self.comboboxMontages.bind('<<ComboboxSelected>>', lambda event: self.change_Montage_combobox(event))
self.comboboxMontages.pack()
self.comboboxMontages.set('Who is my friend')
#-------------------------first combobox end
#-------------------------second combobox start
def highPassFilter_Change_combobox(self, event): # this method goes inside def montage_Combo(self):
myvar = (self.combobox_HPFilter.get())
function_name = self.highPassFilterDict[myvar] # 1
an_object = StartPage(self, tk.Frame) # 2
class_method = getattr(StartPage, function_name) # 3
highPassFilter_result = class_method(an_object) # 4
def highPassFilter_Combo(self):
self.highPassFilter_selector = tk.StringVar()
self.combobox_HPFilter = ttk.Combobox(self, values=sorted(list(self.highPassFilterDict.keys())),
justify="center", textvariable=self.highPassFilter_selector,
state="readonly")
self.combobox_HPFilter.bind('<<ComboboxSelected>>', lambda event: self.highPassFilter_Change_combobox(event))
self.combobox_HPFilter.pack()
self.combobox_HPFilter.set('I´m your friend')
#-------------------------second combobox end
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.montagesDict = {'SpongeBob': 'make_guess01',
'Hommer': 'make_guess02'
}
self.highPassFilterDict = {'Patrick': 'make_guess03',
'Ned Flanders': 'make_guess04',
}
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="how reset lower combobox clicking upper combobox?",
command=self.labels_reset)
button1.pack()
self.montage_Combo()
self.highPassFilter_Combo()
#class PageOne just to make code play
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Python is both challenging and exciting, it seems a zen Koan. After "lots of try an error" and frustration...comes the light.
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
from tkinter import ttk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
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 = {}
for F in (StartPage, PageOne):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def make_guess01(self):
print("I've got a cute friend")
def make_guess02(self):
print('Ned is correct')
def make_guess03(self):
print('Patrick')
def make_guess04(self):
print('Best Hommer friend')
def labels_reset(self):
self.combobox_HPFilter.set('I´m your friend')
#-------------------------first combobox start
def change_Montage_combobox(self, event): # this method goes inside def montage_Combo(self):
myvar = (self.comboboxMontages.get())
# lines 1 2 3 4 say that values(function_name) in montageDict are functions in StartPage
function_name = self.montagesDict[myvar] #1 returns the function(method) in montageDic(value of key:value pair)
# just for reference: print(function_name)--> montage_Original (dictionary montagesDict value)
an_object = StartPage(self, tk.Frame) # 2--> the page (class) where function is
class_method = getattr(StartPage, function_name) # 3 returns method and says the page of the method
result = class_method(an_object) # 4 result is the method right for use
#################################
# answer: #
#################################
if self.combobox_HPFilter != '':
self.labels_reset()
else:
pass
def montage_Combo(self):
self.montage_selector = tk.StringVar()
self.comboboxMontages = ttk.Combobox(self, values=sorted(list(self.montagesDict.keys())),
justify="center", textvariable=self.montage_selector, state="readonly",
)
self.comboboxMontages.bind('<<ComboboxSelected>>', lambda event: self.change_Montage_combobox(event))
self.comboboxMontages.pack()
self.comboboxMontages.set('Who is my friend')
#-------------------------first combobox end
#-------------------------second combobox start
def highPassFilter_Change_combobox(self, event): # this method goes inside def montage_Combo(self):
myvar = (self.combobox_HPFilter.get())
function_name = self.highPassFilterDict[myvar] # 1
an_object = StartPage(self, tk.Frame) # 2
class_method = getattr(StartPage, function_name) # 3
highPassFilter_result = class_method(an_object) # 4
def highPassFilter_Combo(self):
self.highPassFilter_selector = tk.StringVar()
self.combobox_HPFilter = ttk.Combobox(self, values=sorted(list(self.highPassFilterDict.keys())),
justify="center", textvariable=self.highPassFilter_selector,
state="readonly")
self.combobox_HPFilter.bind('<<ComboboxSelected>>', lambda event: self.highPassFilter_Change_combobox(event))
self.combobox_HPFilter.pack()
self.combobox_HPFilter.set('I´m your friend')
def all_ComboBox_labels_reset(self):
self.combobox_HPFilter.set('I´m your friend')
#-------------------------second combobox start
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.montagesDict = {'SpongeBob': 'make_guess01',
'Hommer': 'make_guess02'
}
self.highPassFilterDict = {'Patrick': 'make_guess03',
'Ned Flanders': 'make_guess04',
}
label = tk.Label(self, text="This is the start page")
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="how reset lower combobox clicking upper combobox?",
command=self.labels_reset)
button1.pack()
self.montage_Combo()
self.highPassFilter_Combo()
#class PageOne just to make code play
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1")
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
I used method self.combobox_HPFilter != '': because in my code there are multiple comboboxes to be reseted. "If" because at beginnig of script they are empty.
Excuse me I dont get the (-1)in my question, it is a question. It was usefull to me a beginner and no one answered until I found the answer. Indulge me and be more proactive explaining it. Best.

Is there a way to change window title with multiple frames

I'm trying to create a window with multiple frames in tkinter. But the window title remains the same for any active frame.
The code is used for reference is here.
I tried to add
self.container.title(title)
in respective Pages classes. but the window get the title which was specified the latest.
'''
Solution from...
https://stackoverflow.com/questions/7546050/switch-between-two-frames-in-tkinter
'''
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
#import Tkinter as tk # python 2
#import tkFont as tkfont # python 2
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
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 = {}
for F in (StartPage, PageOne, PageTwo):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.controller.title("Start Page")
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.controller.title("Page One")
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.controller.title("Page Two")
label = tk.Label(self, text="This is page 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Here I expected it to have title of the window to change whenever the frame changed but it prints the title as "Page Two" for entire time even I jump from one frame to another.
Yes, you can use the parameter page_name to change the title of the app when a frame changes
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
self.title(page_name) # update the app title

Tkinter multiple frames/'pages': using canvas images

I would like to employ multiple frames in a GUI, where the page switches depending on the button clicked. I know that there's several threads already about this, and I've been looking at this one.
However, for my pages, I need different images on canvasses within each of my frames, so that when I raise a different frame, it comes with a new canvas and a new image on that canvas. I've tried a lot but I don't know how to get it to work so that the canvasses appear with their images.
Here's what I have so far, mostly copying from above link:
import tkinter as tk # python3
TITLE_FONT = ("Helvetica", 18, "bold")
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
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["StartPage"] = StartPage(parent=container, controller=self)
self.frames["PageOne"] = PageOne(parent=container, controller=self)
self.frames["PageTwo"] = PageTwo(parent=container, controller=self)
self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")
self.frames["PageOne"].grid(row=0, column=0, sticky="nsew")
self.frames["PageTwo"].grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self._canvas = tk.Canvas(parent, bg='white', width=900, height=3517, scrollregion=(0, 2800, 100, 800))
self._photo = tk.PhotoImage(file='images/homegraphic.gif')
self._canvas.create_image(0, 0, image=self._photo, anchor='nw')
label = tk.Label(self, text="This is the start page", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
How do I get the canvas image to appear? I've spent a long time trying to figure this out and would appreciate any help!
The problem is here:
self._canvas = tk.Canvas(parent, ...)
Everything within a page needs to be a child of the page or one of its descendants.
It needs to be this:
self._canvas = tk.Canvas(self, ...)

How to open and close another window with scrollbar in tkinter for python 3.5.?

I want to build a Tkinter app in python 3.5. with a StartPage and a another window PageTwo that includes a table with a scolldownbar. I have tried to apply a framework from an online tutorial and the listbox example from another website.
My problem is: when I run the program both pages are loaded directly. How can I manage to let PageTwo only open on click on Button in StartPage, and then apply another button in PageTwo that closed PageTwo again and redirects to StartPage?
Second question: Alternatively to the listbox example I would like to use canvas with scrollbar on PageTwo. But how and where do I have to introduce the canvas? I get totally messed up with all the inheritances throughout the different classes.
If you would suggest a complete different setup, this would also be fine.
Many thanks for your help.
import tkinter as tk
class GUI(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 = {}
for F in (StartPage, PageTwo):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
frame = StartPage(container, self)
self.frames[StartPage] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise() # zeigt Frame oben an
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Your choice?")
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Open PageTwo",
width = 25, command=lambda: controller.show_frame(PageTwo))
button1.pack(pady=10, padx=10)
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
master = tk.Tk()
scrollbar = tk.Scrollbar(master)
scrollbar.pack(side=tk.RIGHT, fill="y")
listbox = tk.Listbox(master, yscrollcommand=scrollbar.set)
for i in range(1000):
listbox.insert(tk.END, str(i))
listbox.pack(side=tk.LEFT, fill="both")
scrollbar.config(command=listbox.yview)
if __name__ == '__main__':
app = GUI()
app.mainloop()
To fix the issues:
initialize PageTwo only when the button is clicked
use Toplevel for popup window
use root as the StartPage
Below is a demo based on your posted code:
import tkinter as tk
from tkinter import ttk
class GUI(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)
label = tk.Label(self, text="Your choice?")
label.pack(pady=10,padx=10)
button1 = ttk.Button(self, text="Open PageTwo", width=25, command=lambda: self.show_frame(PageTwo))
button1.pack(pady=10, padx=10)
button2 = ttk.Button(self, text="Open PageCanvas", width=25, command=lambda: self.show_frame(PageCanvas))
button2.pack(pady=10, padx=10)
def show_frame(self, page):
win = page(self)
# make window modal
win.grab_set()
self.wait_window(win)
class PageTwo(tk.Toplevel):
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
self.title('Two')
scrollbar = tk.Scrollbar(self)
scrollbar.pack(side=tk.RIGHT, fill="y")
listbox = tk.Listbox(self, yscrollcommand=scrollbar.set)
for i in range(1000):
listbox.insert(tk.END, str(i))
listbox.pack(side=tk.LEFT, fill="both")
scrollbar.config(command=listbox.yview)
class PageCanvas(tk.Toplevel):
def __init__(self, parent):
tk.Toplevel.__init__(self, parent)
self.title('Canvas')
self.geometry('400x600')
canvas = tk.Canvas(self, bg='white', scrollregion=(0, 0, 400, 20000))
canvas.pack(fill='both', expand=True)
vbar = tk.Scrollbar(canvas, orient='vertical')
vbar.pack(side='right', fill='y')
vbar.config(command=canvas.yview)
canvas.config(yscrollcommand=vbar.set)
for i in range(1000):
canvas.create_text(5, i*15, anchor='nw', text=str(i))
if __name__ == '__main__':
app = GUI()
app.mainloop()

Resources