NameError: name 'clear_message' is not defined - python-3.x

from Tkinter import *
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 I 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 (MainPage,StorageOrMotor,Storage,Motor):
page_name = F.__name__
frame = F(container, 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("MainPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class MainPage(tk.Frame):
global user_key
global psw_key
user_key=""
psw_key=""
#Here is the defined for clear_message `def`
def clear_message():
user_key.delete(0, 'END')
psw_key.delete(0, 'END')
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
Username = tk.Label(self, text="Username:",font=("Helvetica", "20","bold"))
Username.grid(row=2, column=3,columnspan=2)
Password = tk.Label(self, text="Password:",font=("Helvetica", "20","bold"))
Password.grid(row=3, column=3,columnspan=2)
#............
Username_key = tk.Entry(self, textvariable = user_key, width=19, font=("Helvetica", "15"))
Username_key.grid(row=2, column=5,columnspan=5)
Password_key = tk.Entry(self, textvariable = psw_key, width=19, font=("Helvetica", "15"))
Password_key.grid(row=3, column=5,columnspan=5)
log_in = tk.Button(self, width=7, text="Log In", command=lambda: controller.show_frame("StorageOrMotor"))
log_in.grid(row=5,column=8,columnspan=2)
#............`I try to create a clear button`
Clear = tk.Button(self, width=7, text=" Clear " ,command=lambda:clear_message())
Clear.grid(row=5,column=5,columnspan=2)

clear_message() belongs to MainPage class so when calling it inside that class, you need to use self. prefix. Also, you need to use self as a parameter when defining the method since it is a member of a class.
def clear_message(self): #self here
user_key.delete(0, 'END')
psw_key.delete(0, 'END')
Additionally, since clear_message doesn't take any arguments, you don't need a lambda expression there.
#self here and removed lambda
Clear = tk.Button(self, width=7, text=" Clear " ,command=self.clear_message)

Related

Tkinter need to update a box based on whats typed in another box on another page

I have some pages in a container, and I want the name box that the user is allowed to type into from one of my pages to update and be displayed on the other page. This is not a variable in all my pages, this is only something I want displayed in 1 of my pages. My app has many pages, but this is my minimal reproducible example of my problem.
I know when my "template" page is created, the text in the name box is blank, so I need to somehow pass the variable when the 'load_page' function is called, but I cannot figure out how to make this work. Any help is appreciated.
The code below gives the error: AttributeError: type object 'template' has no attribute 'name_box' - The problem I have is I do not know how to specify the name box from one page to grab the entered text, and then insert it into another box in another page.
See code below:
import tkinter as tk
from tkinter import font as tkfont, filedialog, messagebox
class SLS_v1(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title('SLS')
self.geometry("552x700")
self.resizable(False, False)
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 = {}
self.frames["MenuPage"] = MenuPage(parent=container, controller=self)
self.frames["template"] = template(parent=container, controller=self)
self.frames["MenuPage"].grid(row=0, column=0, sticky="nsew")
self.frames["template"].grid(row=0, column=0, sticky="nsew")
self.show_frame("MenuPage")
def show_frame(self, page_name):
'''Show a frame for the given 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
name_label = tk.Label(self, text='Name:')
name_label.pack(pady=(20,0))
self.name_var = tk.StringVar()
self.name_entry = tk.Entry(self, width=10, textvariable=self.name_var)
self.name_entry.pack()
template = tk.Button(self, text='Template', height=3, width=20, bg='white', font=('12'),
command=lambda: self.load_page(controller))
template.pack(pady=50)
def load_page(self, controller):
controller.show_frame('template')
template.name_box.insert(tk.END, self.name_entry.var.get())
class template(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.grid(columnspan=10, rowspan=10)
top = tk.Label(self, height=3, width=80, bg='dark grey')
top.grid(row=0, column=0, columnspan=10)
self.back_btn = tk.Button(self, text='BACK', font=('Helvetica', '14'), bg='dark grey',
command=lambda: controller.show_frame('MenuPage'))
self.back_btn.grid(row=0, column=0, columnspan=2, padx=10, pady=10)
name_var = tk.StringVar()
name_box = tk.Entry(self, width=10, textvariable=name_var)
name_box.grid(row=1, column=1)
if __name__ == "__main__":
app = SLS_v1()
app.mainloop()
Edit: Fixed error in code.
You can solve this by importing GC and changing the function that is called when you click the template button to adding these few lines:
import gc
...
...
def load_page(self, controller):
controller.show_frame('template')
for obj in gc.get_objects():
if isinstance(obj, template):
obj.name_box.delete(0, tk.END)
obj.name_box.insert(tk.END, self.name_entry.get())

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.

switching windows in tkinter with classes

in a [former question][1] received a perfect script from #acw1668 for creating popup-windows (see below).
How can this be rewritten in a form that the new windows are not popups but just a switch from one page to the next (the listboxes/candvas are not necessarily needed here)?
Edit: tried to amend the code according to #Bryan Oakley's suggestions.
My issue here: I do not manage to pass the list lst from the GUI class to the other page classes without an error message:
File "/.spyder-py3/temp.py", line 25, in __init__
frame = F(parent=container, controller=self)
TypeError: __init__() missing 1 required positional argument: 'lst'
What am I missing here?
And I do not understand what's happening here:
for F in (StartPage, PageOne, PageTwo):
page_name = F.__name__
frame = F(parent=container, controller=self,)
self.frames[page_name] = frame
If somebody could explain, please?
import tkinter as tk
from tkinter import ttk
class GUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.lst = ['a', 'b', 'c']
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", self.lst)
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
def show_popup(self, page, lst):
win = page(self, lst)
win.grab_set() # make window modal
self.wait_window(win) # make window modal
class StartPage(tk.Frame):
def __init__(self, parent, controller, lst):
tk.Frame.__init__(self, parent)
self.controller = controller
self.lst = lst
# ------------------------------------------------------------------- #
label = tk.Label(self, text="Check this out")
label.pack(pady=10,padx=10)
# ------------------- create buttons ---------------------------------
button1 = ttk.Button(self, text="show all",
width = 25, command=lambda:
controller.show_popup(App, self.lst))
button1.pack(pady=10, padx=10)
button2 = ttk.Button(self, text="show page one",
width = 25, command=lambda:
controller.show_frame(PageOne))
button2.pack(pady=10, padx=10)
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()
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")
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 App(tk.Toplevel):
def __init__(self, parent, lst):
tk.Toplevel.__init__(self, parent)
self.lst = lst
self.title('This is the pop up window')
self.geometry('400x200')
label = tk.Label(self, text=self.lst)
label.pack(side="top", fill="x", pady=10)
parent.grid_rowconfigure(0, weight = 1)
parent.grid_columnconfigure(0, weight = 1)
if __name__ == '__main__':
app = GUI()
app.mainloop()
[1]: http://stackoverflow.com/questions/41181809/how-to-open-and-close-another-window-with-scrollbar-in-tkinter-for-python-3-5/41182843?noredirect=1#comment69580999_41182843
Your class initializers are defined like this:
class StartPage(tk.Frame):
def __init__(self, parent, controller, lst):
In order to create an instance of this class it requires three arguments (plus self): parent, controller, and lst.
Now, let's look at how you're creating the instance:
frame = F(parent=container, controller=self,)
Notice how you have the parent and you have the controller, but you haven't passed in anything for lst. That is why the error states "missing 1 required positional argument: 'lst'" -- because you are literally missing one required argument named "lst".
To fix this problem, you simply need to provide this extra argument. For example:
frame = F(parent=container, controller=self, lst=self.lst)
HOWEVER, you probably shouldn't do that. The architecture of this little block of code you copied makes it possible to access values on the GUI class from any of the "page" classes without having to do any extra work.
Because this variable is an attribute of the GUI class, and you are passing a reference to the instance of the GUI class to each "page" (the controller attribute), you can access this data any time you want without having to pass it in at construction time. You can remove it from __init__ and from where you're creating the pages (ie: go back to the original code before your modifications), and then just use self.controller.lst whenever you need the value.
For example:
class SomePage(tk.Frame):
def __init__(self, parent, controller):
self.controller = controller
...
def some_function(self):
print("The value of 'lst' is:", self.controller.lst)

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()

Scrollbar - tkinter GUI - Python 3

I've been trying to create a scrollbar on a frame by trying to combine two codes written by Bryan Oakley. ( The code is not mine).
The first one is code the creates multiple frame using classes and the other one uses canvas to create a scrollable frame.
import tkinter as tk
class SampleApp(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, Example):
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()
The original code for does not use parent nor controller as parameters but uses roots instead. By switching to parent and controller the labels created in the function "inmatning" are moved all the way to the write and the scrollbar doesn't show.
class Example(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff")
self.frame = tk.Frame(self.canvas, background="#ffffff")
self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.inmatning()
def inmatning(self):
allbio = läs_fil()
x = 0
while x < len(allbio):
label = tk.Label(self, text="\n"+allbio[x].namn)
label.pack()
lista =["Barn", "Vuxna", "Penionärer"]
l = 0
while l < len(lista):
label1= tk.Label(self, text="Antal " + lista[l])
label1.pack()
enter1 = tk.Entry(self)
enter1.pack()
l=l+1
x=x+1
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
This here is normal frame that works without any problem ( not using canvas of course )
class Menu(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Här kan du väljer mellan de följande 6 alternativen")
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Example",
command=lambda: controller.show_frame("Example"))
button1.pack()
button2 = tk.Button(self, text="Beläggning",
command=lambda: controller.show_frame("Beläggning"))
button2.pack()
Take a look at this code:
def inmatning(self):
...
while x < len(allbio):
label = tk.Label(self, text="\n"+allbio[x].namn)
What is it doing? It is creating some labels, each with a parent of self. What is self? It's a frame that has an canvas, and inside that canvas is a frame. Widgets that are inside that inner frame will be scrolled when the canvas is scrolled.
The whole point of the scrollable frame is that put put widgets in the inner frame, not in the outer frame. It's the inner frame (the one inside the canvas) that should contain all of the widgets.
Try changing your label creation to this:
label = tk.Label(self.frame, text="\n"+allbio[x].namn)
I don't know if that's the only problem, but it's certainly part of the problem. I can't simply cut and paste your code to test it out since you have code spread among several blocks, and didn't include all of your code.

Resources