Python frames tkinter - python-3.x

Im having troubles with tkinter frames
The folowing code must display labels at left side and there should be more space the button and the label , there is something wrong with my column/row setup. What am i doing wrong?
What is the correct way for a program to display information? 1 global frame with several smaller frames in it? With tkinter when using a menu with page 1 page 2 and page 3 ,
page 1 has 3 input fields , child of FramePage1 , page 2 has 2 buttons child of FramePage2, page 3 has one big text field child of FramePage3. Is it the correct way to use for changing the pages
#menu tab1 -> command #calls function page1
def page1():
self.Framepage2.grid_forget()
self.Framepage1.grid()
#content of the page
or are there other ways to use different layout style pages?
import tkinter
import tkinter as tk
class sjabloon():
def __init__(self):
#make window
self.win = tk.Tk()
self.win.geometry("600x600+10+10")
#make top frame
self.frame_header = tk.Frame(self.win, background='black', width=600, height=50)
self.frame_header.grid(column=0, row=0 , columnspan= 10)
#make body frame
self.frame_body = tk.Frame(self.win, width=600, height=400)
self.frame_body.grid(column=0, row=1 , columnspan= 10)
#button1 select
tk.Label(self.frame_body, text="Select:").grid(column=0, row=2, stick='W')
self.button1 = tk.Button(self.frame_body, text="Select")
self.button1.grid(row=2, column=5, stick='W')
#button1 select
tk.Label(self.frame_body, text="Select:").grid(column=0, row=3, stick='W')
self.button2 = tk.Button(self.frame_body, text="Select")
self.button2.grid(row=4, column=5, stick='W')
#button submit
self.submit = tk.Button(self.frame_body, text="Start")
self.submit.grid(row=10, column=9, stick='W')
#make body footer
self.frame_footer = tk.Frame(self.win, background='yellow', width=600, height=50)
self.frame_footer.grid(column=0, row=3 , columnspan= 10)
if __name__ == "__main__":
sjabloon = sjabloon()

I suggest you to follow this tkinter GUI tutorial, he makes a pretty big app and even if it's not what you exactly looking for, it will help you.
In the part 4, he make a multiple frame architecture in the tkinter GUI.
For switching "pages", i know 2 choices (there's more i think but i don't know them, i'm still a beginner). You can create all the frames inside a window/Frame and raise to the front the one you want (that's in the tutorial part 4) or you can destroy the widgets "Page 1" inside the body frame and create the widgets "Page 2" inside it (obviously in methods/functions to let you switch between the pages).
For your first problem, i'm not sure if i understand your problem, you want more space around your button widget ? if that's what you want, you can use the option padx=(leftPadx,RightPadx) like that :
self.button1.grid(row=2, column=5, stick='W', padx=(50,0))
EDIT : i made a little architecture for you (from what i learn in that tutorial)
Basically, you create all the "Page", you add them in the bodyFrame and you raise to the front the one you want. To achieve that, for each "Page", you create a class that inherits tk.Frame and you add an instance of that class in the mainWindow
import tkinter as tk
from tkinter import ttk
LARGE_FONT = ("Verdana 12")
NORM_FONT = "Verdana 10"
SMALL_FONT = ("Verdana 8")
ERROR_404 = "Error 404 : Page not found !"
class sjabloon(tk.Tk):
def __init__(self, *args, **kwargs):
#make window
tk.Tk.__init__(self, *args, **kwargs)
self.geometry("600x600+10+10")
#make top frame
self.frame_header = tk.Frame(self, background='black', width=600, height=50)
self.frame_header.grid(column=0, row=0 , columnspan= 10)
#make body frame
container = tk.Frame(self, width=600, height=400)
container.grid(column=0, row=1 , columnspan= 10)
#list of Pages
self.frames = {}
#everytime you create a "Page", you add it there
for F in (StartPage, HomePage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=1, column = 0, sticky="nsew", columnspan= 10)
self.show_page("StartPage")
#make body footer
self.frame_footer = tk.Frame(self, background='yellow', width=600, height=50)
self.frame_footer.grid(column=0, row=3 , columnspan= 10)
def show_page(self, page_name):
"""
let us use the NAME of the class to display(the function show_frame
use directly the class).
when we use the classe name, we can put our classes in defferent
files
"""
for F in self.frames:
if F.__name__ == page_name:
self.show_frame(F)
return
print(ERROR_404)
def show_frame(self, cont):
"""raise to the front the frame we want
:param cont: the frame
"""
frame = self.frames[cont]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#button1 select
tk.Label(self, text="Select:").grid(column=0, row=2, stick='W')
self.button1 = tk.Button(self, text="Select")
self.button1.grid(row=2, column=5, stick='W', padx=(50,0))
#button1 select
tk.Label(self, text="Select:").grid(column=0, row=3, stick='W')
self.button2 = tk.Button(self, text="Select")
self.button2.grid(row=4, column=5, stick='W', padx=(50,0))
#button submit
self.submit = tk.Button(self, text="Start")
self.submit.grid(row=10, column=9, stick='W')
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="""ALPHA application.
use at your own risk. There is no promise
of warranty""", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = ttk.Button(self, text="Agree",
command=lambda: controller.show_page("HomePage"))
button1.pack()
button2 = ttk.Button(self, text="Disagree",
command=controller.destroy)
button2.pack()
if __name__ == "__main__":
sjabloon = sjabloon()
sjabloon.mainloop()

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

How to get/ print a current value in a tkinter radiobutton

I am trying to print a current value of a radiobutton in a oop structured application. I have seen a couple of solutions on how to write a working code (for example https://www.tutorialspoint.com/python/tk_radiobutton.htm) but when I try to use it in my classes I am doing something wrong.
I have the following background code:
class OutFileGUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, ".Out GUI")
container = tk.Frame(self)
container.pack(side='top', fill='both', expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
menubar = tk.Menu(container)
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label="Read file", command=self.open_file)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=quit)
menubar.add_cascade(label="File", menu=filemenu)
tk.Tk.config(self, menu=menubar)
self.frames = {}
for F in (StartPage, MainPage, ConvBehaviour, GaussPoints):
frame = F(parent=container, controller=self) =
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
def get_page(self, page_class):
return self.frames[page_class]
def open_file(self):
name = askopenfilename(
filetypes=((".Out File", "*.out"), ("All Files", "*.*")),
title="Choose a file.")
message = ("File location: " + str(name))
print(message)
In the frame below I am trying to place a radiobutton and depending on the selected value by a user print the value.
class ConvBehaviour(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="See behaviour", font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = ttk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(MainPage))
button1.pack()
button2 = ttk.Button(self, text="See points statistics",
command=lambda: controller.show_frame(GaussPoints))
button2.pack()
norms = [("norm 1", 1),
("norm 2", 2),
("norm 3", 3)]
#Here is the problem
self.v1 = tk.IntVar()
self.v1.set(1)
for text, num in norms:
radiobutton = tk.Radiobutton(self, text=text, value=num, variable=self.v1, command=self.show_choice)
radiobutton.pack()
def show_choice(self):
print('int ' + str(self.v1.get()))
The problem I have is that the method show_choice(self) does not work in the current implementation. It prints the current value set in self.v1.set(1) instead of either of 1, 2, 3 depending on a user selection. Where does the problem lie?
Try to build a minimal example as possible such that the problem of the variable not catching the user input still showing up while removing as much background noise as possible. See also https://stackoverflow.com/help/mcve
For example, the most minimal example only containing the radiobuttons I can build from your code is the following (and it is working as intended):
import tkinter as tk
def main():
root = tk.Tk()
norms = [("norm 1", 1),
("norm 2", 2),
("norm 3", 3)]
v1 = tk.IntVar()
v1.set(1)
def show_choice():
print('int ' + str(v1.get()))
for text, num in norms:
radiobutton = tk.Radiobutton(root, text=text, value=num, variable=v1,
command=show_choice)
radiobutton.pack()
root.mainloop()
if __name__ == '__main__':
main()
Try to build from there up - in small steps (maybe first try to add your own class inheriting from tk.Frame, etc.). This is essential: dont copy big chunks of code (with confusing classes and conventions) from someone else, but start from small working examples and work upwards.

Refresh a tkinter frame on button press

I am utilising code from Switch between two frames in tkinter to make my GUI. I have a frame with refresh and restart buttons.
My original idea was for the restart button to go to the start page as in the code below but if this frame is called again it has the entries from the previous attempt still showing.
I've tried.destroy() for the refresh button but then I get an traceback message when I call the PLG frame again.
For the restart button, how would I close the PLG frame, go to the Start page and then be able to select PLG again?
For the refresh button, how would I remove the entries in the entry widget and text arrear so that another entry can be made and new answer returned?
class PLG(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Enter the engine size (cc) below", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
vcmd = (self.register(self.onValidate), '%S')
self.weight_entry = tk.Entry(self, validate='key', vcmd = vcmd)
self.weight_entry.pack(pady = 10)
tk.Button(self, text='Click here to display price', command=self.show_option).pack()
self.text = tk.Text(self)
self.text.pack(pady = 10)
self.text.config(state='disabled')
restart_button = tk.Button(self, text="Restart",
command=self.restart)
restart_button.pack()
refresh_button = tk.Button(self, text="Refresh", command=self.refresh).pack()
refresh_button.pack()
def onValidate(self,S):
if S in ['0','1','2', '3', '4', '5', '6', '7', '8', '9']:
return True
else:
self.bell() # adds a sound effect to error
self.text.delete(1.0, tk.END) # deletes the error message if valid entry provided
self.text.insert(tk.END, "Invalid entry. Please try again.") # displays an error message if a number not provided in entry widget
return False
def restart(self):
self.refresh()
show_frame("StartPage")
def refresh(self):
self.text.config(state='normal')
self.weight_entry.delete(0,tk.END)
self.text.delete("1.0", "end")
Advice on both elements would be appreciated.
The OP's question was about clearing input fields so prior input isn't still in the page when you expected to see empty fields for fresh input. I'm posting the finished code while omitting features of the OP's original code which were irrelevant to his question so the solution could easily be seen in its full context. I had been looking to solve this problem with this same frame-switching code from Bryan Oakley's famed tutorials on this topic. I also included an alternate version using grid_remove instead of tkraise since this is how I had solved the problem of ever-active but unseen frames trying to participate in the focus traversal as the user tries to tab through the page. It also kept the frames from all trying to be the same size.
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 = {}
# alternate ways to create the frames & append to frames dict: comment out one or the other
for F in (StartPage, PLG):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
# self.frames["StartPage"] = StartPage(parent=container, controller=self)
# self.frames["PLG"] = PLG(parent=container, controller=self)
# self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")
# self.frames["PLG"].grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
# alternate version of show_frame: comment out one or the other
def show_frame(self, page_name):
for frame in self.frames.values():
frame.grid_remove()
frame = self.frames[page_name]
frame.grid()
# def show_frame(self, 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="start page")
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One", command=lambda: controller.show_frame("PLG"))
button1.pack()
button2 = tk.Button(self, text="focus traversal demo only")
button2.pack()
button2.focus_set()
button3 = tk.Button(self, text="another dummy button")
button3.pack()
lbl = tk.Label(self, text="tkraise messes up focus traversal\nwhich you can see by testing the two versions of show_frame.()\nUsing grid_remove instead of tkraise solves that,\nwhile preventing frames from being unable to resize to fit their own contents.")
lbl.pack()
class PLG(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Enter something below; the two buttons clear what you type.")
label.pack(side="top", fill="x", pady=10)
self.wentry = tk.Entry(self)
self.wentry.pack(pady = 10)
self.text = tk.Text(self)
self.text.pack(pady = 10)
restart_button = tk.Button(self, text="Restart", command=self.restart)
restart_button.pack()
refresh_button = tk.Button(self, text="Refresh", command=self.refresh)
refresh_button.pack()
def restart(self):
self.refresh()
self.controller.show_frame("StartPage")
def refresh(self):
self.wentry.delete(0, "end")
self.text.delete("1.0", "end")
# set focus to any widget except a Text widget so focus doesn't get stuck in a Text widget when page hides
self.wentry.focus_set()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
The first step is to have your button call a proper function rather than using lambda. Unless you understand why and when to use lambda, it usually just makes the code harder to write and understand.
Once you have it call a function, you can use the function to clear the entries.
Example:
class PLG(tk.Frame):
def __init__(self, parent, controller):
...
tk.Button(self, text="Restart", command=self.restart)
tk.Button(self, text="Refresh", command=self.refresh)
...
def restart(self):
self.refresh()
self.controller.show_frame("StartPage")
def refresh(self):
self.weight_entry.delete(0, "end")
self.text.delete("1.0", "end")
Simple way:
Just call that window with button or bind in which frame lies.
works good for windows refresh.

How to display a dataframe in tkinter

I am new to Python and even newer to tkinter.
I've utilised code from stackoverflow (Switch between two frames in tkinter) to produce a program where new frames are called and placed on top of each other depending on what options the user selects. A stripped down version of my code is below. There are a lot more frames.
import tkinter as tk
from tkinter import font as tkfont
import pandas as pd
class My_GUI(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, Page_2):
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 __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Welcome to....", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Option selected",
command=lambda: controller.show_frame("Page_2"))
button1.pack()
class Page_2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="The payment options are displayed below", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
#I want the able to be display the dataframe here
button = tk.Button(self, text="Restart",
command=lambda: controller.show_frame("StartPage"))
button.pack()
a = {'Option_1':[150,82.50,150,157.50,78.75],
'Option2':[245,134.75,245,257.25,128.63]}
df = pd.DataFrame(a,index=['a',
'b',
'c',
'd',
'e'])
print(df.iloc[:6,1:2])
if __name__ == "__main__":
app = My_GUI()
app.mainloop()
When Page_2 appears I want it to display a dataframe with the code below.
a = {'Option_1':[150,82.50,150,157.50,78.75],
'Option2':[245,134.75,245,257.25,128.63]}
df = pd.DataFrame(a,index=['a',
'b',
'c',
'd',
'e'])
print(df.iloc[:6,1:2])
I've searched SO e.g. How to display a pandas dataframe in a tkinter window (tk frame to be precise) (no answer provided) and other websites for an answer to similar question but without success.
How and where would I place my dataframe code selection to appear in the area I want when I select Page_2?
Check out pandastable.
It is quite a fancy library for displaying and working with pandas tables.
Here is a code example from their documentation:
from tkinter import *
from pandastable import Table, TableModel
class TestApp(Frame):
"""Basic test frame for the table"""
def __init__(self, parent=None):
self.parent = parent
Frame.__init__(self)
self.main = self.master
self.main.geometry('600x400+200+100')
self.main.title('Table app')
f = Frame(self.main)
f.pack(fill=BOTH,expand=1)
df = TableModel.getSampleData()
self.table = pt = Table(f, dataframe=df,
showtoolbar=True, showstatusbar=True)
pt.show()
return
app = TestApp()
#launch the app
app.mainloop()
and here a screenshot (also from their docs):
As a start, you could have a look at Label and Text widgets, that usually are used to display text in your GUI.
You could probably try something like:
class Page_2(tk.Frame):
def __init__(self, parent, controller):
# ... your code ...
global df # quick and dirty way to access `df`, think about making it an attribute or creating a function that returns it
text = tk.Text(self)
text.insert(tk.END, str(df.iloc[:6,1:2]))
text.pack()
# lbl = tk.Label(self, text=str(df.iloc[:6,1:2])) # other option
# lbl.pack() #
In the end, it really boils down to how fancy you want to be: the widgets are highly customizable, so you could achieve something very pleasing to the eye instead of the basic look of this example.
Edit:
I added a Combobox widget to select the option to display and a Button that prints it to the "display" widget of your choice.
from tkinter import ttk # necessary for the Combobox widget
# ... your code ...
class Page_2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="The payment options are displayed below", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
global df
tk.Label(self, text='Select option:').pack()
self.options = ttk.Combobox(self, values=list(df.columns))
self.options.pack()
tk.Button(self, text='Show option', command=self.show_option).pack()
self.text = tk.Text(self)
self.text.pack()
tk.Button(self, text="Restart",
command=lambda: controller.show_frame("StartPage")).pack()
def show_option(self):
identifier = self.options.get() # get option
self.text.delete(1.0, tk.END) # empty widget to print new text
self.text.insert(tk.END, str(df[identifier]))
The text that is displayed is the default string representation of a data-frame's column; a custom text is left as an exercise.

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