Freezing the header in a grid with a scrollbar in Tkinter - python

So I finally decided to build a GUI, but I'm stuck bad, and I can't find anything on the internet.
What I'm trying to acomplish is basically the "freeze panes" option from Excel.
I have build a scrollable grid of labels following this guide. But I want the header of the initial grid to stay when I scroll.
I have thought of making a separate grid and place the header in it, but I can't anything other than (0,0,0,0) from bbox (to place them right, because the header might be short while the entries might be long!).
As an alternative to bbox I have thought of "expanding" the titles with something like
title+' '*(len(longest_entry)-len(title)), but that seems highly inefficient if the entry list is huge and probably won't look as pretty if my entry is something like |||||| or WWWWWW due to different size of the characters.
Can you help me with bbox in this case? (what should I use it on?)
Or give me totally different ideas of what to do?
Many thanks in advance!
Sorry for using the deprecated tag header, but I couldn't find an appropiate tag

This is a GUI I'm working on for my tasks list with priority and description that works pretty well. The entry boxes and headers are on separate canvases so that the header will not scroll and the entry boxes will. I had trouble aligning the headers with the entries. The short term fix was to use different fonts that happen to align. I still don't know why explicitly setting widths did not work.
import Tkinter as Tk
from Tkinter import StringVar
#-----------------------------------------------------------------------------
# Scroll entry boxes with mouse wheel
# canvas1, frame1
#
# Header row is on a separate canvas and will not scroll with entry boxes.
# canvas2, frame2
#
# Could not align header and entries unless different fonts were used.
# Play with variable "font_choice" to see how it works
#-----------------------------------------------------------------------------
# define fonts and other preliminary things
font_choice = 1
if(font_choice == 1): # using same font sizes does not align well
Label_Font = "Arial 10"
Entry_Font = "Arial 10"
if(font_choice == 2): # using different font sizes not exactly aligned, but close
Label_Font = "Arial 9 bold"
Entry_Font = "Arial 10"
if(font_choice == 3): # this does not align well
Label_Font = "Helvetica 10"
Entry_Font = "Helvetica 10"
if(font_choice == 4): # this aligns pretty well (surprisingly)
Label_Font = "Helvetica 14"
Entry_Font = "Helvetica 14"
width_priority = 10
width_time_estimate = 15
width_description_1 = 90
Labels = ["Priority", "Time Est. (mins)", "Description 1"]
Widths = [width_priority, width_time_estimate, width_description_1]
Label_Colors = ["misty rose", "lavender", "lightcoral"]
list_length = 25
canvas_width = 1300
header_height = 25
#------------------------------------------------------------------------------
def populate1(framex):
global entrys_1
global entrys_2
global entrys_3
label_flag = 0 # 1 or 2 are options, 0 is off
ijk_col = 0
if(label_flag == 1):
Tk.Label(framex, text=Labels[ijk_col]).grid(row=0, column=ijk_col)
if(label_flag== 2):
xy1 = Tk.Label(framex, text=Labels[ijk_col], font=Label_Font)
xy1.grid(row=0, column=ijk_col)
xy1.config(width=Widths[ijk_col], borderwidth="1", background=Label_Colors[ijk_col])
entrys_1 = []
variables_1 = []
ii = 0
for row in range(list_length):
rowx = row + 1
variables_1.append(StringVar())
entrys_1.append(Tk.Entry(framex, textvariable=variables_1[ii], font=Entry_Font))
entrys_1[-1].config(width=Widths[ijk_col], borderwidth="1")
entrys_1[-1].grid(row=rowx, column=ijk_col)
entrys_1[-1].config(fg="black", bg=Label_Colors[ijk_col])
entrys_1[-1].delete(0, Tk.END)
entrys_1[-1].insert(0, "Placeholder")
ii += 1
ijk_col = 1
if(label_flag == 1):
Tk.Label(framex, text=Labels[ijk_col]).grid(row=0, column=ijk_col)
if(label_flag== 2):
xy2 = Tk.Label(framex, text=Labels[ijk_col], font=Label_Font)
xy2.grid(row=0, column=ijk_col)
xy2.config(width=Widths[ijk_col], borderwidth="1", background=Label_Colors[ijk_col])
entrys_2 = []
variables_2 = []
ii = 0
for row in range(list_length):
rowx = row + 1
variables_2.append(StringVar())
entrys_2.append(Tk.Entry(framex, textvariable=variables_2[ii], font=Entry_Font))
entrys_2[-1].config(width=Widths[ijk_col], borderwidth="1")
entrys_2[-1].grid(row=rowx, column=ijk_col)
entrys_2[-1].config(fg="black", bg=Label_Colors[ijk_col])
entrys_2[-1].delete(0, Tk.END)
entrys_2[-1].insert(0, "Placeholder")
ii += 1
ijk_col = 2
if(label_flag == 1):
Tk.Label(framex, text=Labels[ijk_col]).grid(row=0, column=ijk_col)
if(label_flag== 2):
xy3 = Tk.Label(framex, text=Labels[ijk_col], font=Label_Font)
xy3.grid(row=0, column=ijk_col)
xy3.config(width=Widths[ijk_col], borderwidth="1", background=Label_Colors[ijk_col])
entrys_3 = []
variables_3 = []
ii = 0
for row in range(list_length):
rowx = row + 1
variables_3.append(StringVar())
entrys_3.append(Tk.Entry(framex, textvariable=variables_3[ii], font=Entry_Font))
entrys_3[-1].config(width=Widths[ijk_col], borderwidth="1")
entrys_3[-1].grid(row=rowx, column=ijk_col)
entrys_3[-1].config(fg="black", bg=Label_Colors[ijk_col])
entrys_3[-1].delete(0, Tk.END)
entrys_3[-1].insert(0, "Placeholder")
ii += 1
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
#-----------------------------------------------------------------------------
root = Tk.Tk()
root.title("StackOverflow_Label_Entry_Align")
#---------------------------------
# set up canvas that scrolls for entries, header on separate canvas that does not scroll
canvas1 = Tk.Canvas(root, borderwidth=0, background="#ffffff", height=400, width=canvas_width)
frame1 = Tk.Frame(canvas1, background="#ffffff")
xscrollbar = Tk.Scrollbar(root, orient=Tk.HORIZONTAL, command=canvas1.xview)
yscrollbar = Tk.Scrollbar(root, orient=Tk.VERTICAL, command=canvas1.yview)
yscrollbar.pack(side=Tk.RIGHT, fill=Tk.Y)
xscrollbar.pack(side=Tk.BOTTOM, fill=Tk.X)
canvas1.configure(xscrollcommand=xscrollbar.set)
canvas1.configure(yscrollcommand=yscrollbar.set)
canvas1.pack(side="bottom", fill="both", expand=True)
canvas1.create_window((4,4), window=frame1, anchor="nw")
frame1.bind("<Configure>", lambda event, canvas=canvas1: onFrameConfigure(canvas))
def _on_mousewheel(event):
canvas1.yview_scroll(-1*(event.delta/120), "units")
canvas1.configure(yscrollincrement='20') # adjust sensitivity
canvas1.bind_all("<MouseWheel>", _on_mousewheel) # Oakley has a post on this
canvas1.focus_set() # key to making canvas bind to left, right keys
#-----------------------------------------------------------------------------
# set up separate canvas for header row that will not scroll
canvas2 = Tk.Canvas(root, borderwidth=0, background="#ffffff", height=header_height, width=canvas_width)
frame2 = Tk.Frame(canvas2, background="#ffffff")
canvas2.pack(side="top", fill="both", expand=True)
canvas2.create_window((0,0), window=frame2, anchor="nw", height=header_height)
x1 = Tk.Label(frame2, text=Labels[0], font=Label_Font)
x1.grid(row=0, column=0)
x1.config(width=Widths[0], borderwidth="1", background=Label_Colors[0])
x2 = Tk.Label(frame2, text=Labels[1], font=Label_Font)
x2.grid(row=0, column=1)
x2.config(width=Widths[1], borderwidth="1", background=Label_Colors[1])
x3 = Tk.Label(frame2, text=Labels[2], font=Label_Font)
x3.grid(row=0, column=2)
x3.config(width=Widths[2], borderwidth="1", background=Label_Colors[2])
#-----------------------------------------------------------------------------
populate1(frame1) # add entry boxes
#-----------------------------------------------------------------------------
root.mainloop()
#-----------------------------------------------------------------------------

Related

Why is my tkinter treeview not changing colors?

I am trying to color my tkinter treeview using tags but it doesn't work even tho I have followed a few tutorials and I think I am doing everything the right way.
self.sidebar_button_event()
self.ultimo = "Inventario"
self.cajas_frame = customtkinter.CTkTabview(self, height=250)
self.cajas_frame.add("Cajas")
self.cajas_frame.tab("Cajas").grid_columnconfigure(0, weight=1)
self.cajas_frame.tab("Cajas").grid_rowconfigure(0, weight=1)
self.cajas_frame.grid(row=0, column=1, padx=(20, 20), pady=(20, 20), sticky="new", columnspan=3)
self.setTablaCajas()
n = 0
for f in self.inventario.datosCajas():
if n % 2 == 0:
self.cajas.insert(parent='', index='end', iid=n, values=f, tags=('par',))
else:
self.cajas.insert(parent='', index='end', iid=n, values=f, tags=('impar',))
self.cajas.bind("<<TreeviewSelect>>", self.clickCajas)
n += 1
n = 0
self.cajas.tag_configure('par', background='orange', )
self.cajas.tag_configure('impar', background='purple')
Could it be because of me using customtkinter and tkinter?
PS: I already tried using Style.configure and it does change it's appearance, but it doesn't seem to work this way and I want odd and even rows to have a different color.
I used a working example to explain the color tag function for the rows:
# Source for base treeview https://www.pythontutorial.net/tkinter/tkinter-treeview/
# extendet with style and color line 11 to 13, 24, 33 to 38 and 60,61
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo
root = tk.Tk()
root.title('Treeview demo')
root.geometry('620x200')
# style the widget
s = ttk.Style()
s.theme_use('clam')
# define columns
columns = ('first_name', 'last_name', 'email')
tree = ttk.Treeview(root, columns=columns, show='headings')
# define headings
tree.heading('first_name', text='First Name')
tree.heading('last_name', text='Last Name')
tree.heading('email', text='Email')
s.configure('Treeview.Heading', background="green3")
# generate sample data
contacts = []
for n in range(1, 100):
contacts.append((f'first {n}', f'last {n}', f'email{n}#example.com'))
# add data to the treeview AND tag the row color
i = 1
for contact in contacts:
i += 1
if i%2:
tree.insert('', tk.END, values=contact, tags = ('oddrow',))
else:
tree.insert('', tk.END, values=contact, tags = ('evenrow',))
def item_selected(event):
for selected_item in tree.selection():
item = tree.item(selected_item)
record = item['values']
# show a message
showinfo(title='Information', message=','.join(record))
tree.bind('<<TreeviewSelect>>', item_selected)
tree.grid(row=0, column=0, sticky='nsew')
# add a scrollbar
scrollbar = ttk.Scrollbar(root, orient=tk.VERTICAL, command=tree.yview)
tree.configure(yscroll=scrollbar.set)
scrollbar.grid(row=0, column=1, sticky='ns')
# style row colors
tree.tag_configure('oddrow', background='lightgrey')
tree.tag_configure('evenrow', background='white')
# run the app
root.mainloop()
Output:

How to remove unwanted scrollable space in Tkinter window

Assume a small Tkinter window with two frames, one having 20 buttons vertically and the other having 100 buttons vertically. These frames be one below the other. The window is small and so I create a scrollbar like this:
from tkinter import*
root = Tk()
root.geometry('200x100')
main_frame = Frame(root)
main_frame.pack(fill = BOTH, expand = 1)
main_canvas = Canvas(main_frame, bg = 'snow')
main_canvas.pack(side = LEFT, fill = BOTH, expand = 1)
vertical_scrollbar = ttk.Scrollbar(main_frame, orient = VERTICAL, command = main_canvas.yview)
vertical_scrollbar.pack(side = RIGHT, fill = Y)
main_canvas.configure(yscrollcommand = vertical_scrollbar.set)
main_canvas.bind('<Configure>', lambda e: main_canvas.configure(scrollregion = main_canvas.bbox("all")))
screen_frame = Frame(main_canvas, bg = 'snow')
main_canvas.create_window((0,0), window = screen_frame, anchor = 'nw')
frame1 = Frame(screen_frame, bg = 'snow').grid(row = 0, column = 0)
frame2 = Frame(screen_frame, bg = 'snow').grid(row = 1, column = 1)
for i in range(0, 20):
Button(frame1, text = 'Button').grid(row = i, column = 0)
for j in range(0, 100):
Button(frame2, text = 'Button').grid(row = j, column = 0)
root.mainloop()
So at this point, we will be able to scroll till the end of the second frame. But Now if I do the following:
for widgets in frame2.winfo_children():
widgets.destroy()
Frame 2 becomes empty. But now the scrollbar doesn't end at the end of frame1. Rather there is an empty space below frame1 where 100 buttons of frame2 used to be.
So my doubt is, how do we remove this empty space?

tkinter collapsible in 3-column layout makes columns jump

For tkinter in python, I created a collapsible widget that shows/hides some content on click. I found an example on this site and adjusted it to my needs.
What I try to do is to put multiple collapsibles into a 3-column layout. The problem is that opening a collapsible in one column causes the other columns to "jump". This effect can be seen when running the example code below. It seems that if the content of the collapsible is longer than the length of both labels in the header of the collapsible (i. e. the text "Collapsed" and the "+" character) the colums begin to jump because the other one is getting expanded. I already experimented with settings like columnspan, sticky, etc. on all different levels of parent and child widgets, but nothing worked.
Does anyone have an idea on how to make the 3-column layout without the "jumping" effect? If there exists a totally different approach to reach the goal, I would be glad to get some hints!
Here is the example code:
import tkinter as tk
# Collapsible class
class Collapsible(tk.Frame):
def __init__(self, parent):
# Call __init__ of parent class
tk.Frame.__init__(self, parent)
# Setting weight to the first column makes the second column "float".
# This puts the "+" and "-" characters to the right of the column.
self.columnconfigure(index=0, weight=1)
# If value=0, collapsible is initially closed.
# If value=1, collapsible is initially opened.
self._variable = tk.IntVar(value=0)
# Frame for clickable header of collapsible
self.header_frame = tk.Frame(self, name='header_frame', bg='yellow')
self.header_frame.columnconfigure(1, weight=1)
self.header_frame.bind('<Button-1>', lambda e: self.toggle())
self.header_frame.grid(row=0, column=0, sticky='ew')
# Frame for content of collapsible
self.content_frame = tk.Frame(self, name='content_frame', bg='green')
# Call _activate method
self._activate()
def _activate(self):
# Remove all child widgets from header frame
for child in self.header_frame.winfo_children():
child.destroy()
# Closed: self._variable.get() = 0
if not self._variable.get():
# Labels in header frame if collapsed
collapsed_header_1 = tk.Label(self.header_frame, text='Collapsed', bg='purple')
collapsed_header_1.bind('<Button-1>', lambda e: self.toggle())
collapsed_header_1.grid(column=0, row=0, sticky='nw')
collapsed_header_2 = tk.Label(self.header_frame, text='+', width=2, bg='purple')
collapsed_header_2.bind('<Button-1>', lambda e: self.toggle())
collapsed_header_2.grid(column=1, row=0, sticky='ne')
# Forget the content frame if collapsible is closed
self.content_frame.grid_forget()
# Opened: self._variable.get() = 1
elif self._variable.get():
# Labels in header frame if expanded
expanded_header_1 = tk.Label(self.header_frame, text='Expanded', bg='purple')
expanded_header_1.bind('<Button-1>', lambda e: self.toggle())
expanded_header_1.grid(column=0, row=0, sticky='nw', )
expanded_header_2 = tk.Label(self.header_frame, text='-', width=2, bg='purple')
expanded_header_2.bind('<Button-1>', lambda e: self.toggle())
expanded_header_2.grid(column=1, row=0, sticky='ne')
# Show/expand the content frame if collapsible is opened
self.content_frame.grid(row=1, column=0, sticky='new', columnspan=2)
def toggle(self):
# Change value of self._variable and call self._activate
self._variable.set(not self._variable.get())
self._activate()
# Test the collapsible
if __name__ == "__main__":
# Create app and give it a name
app = tk.Tk()
app.title("Collapsible Test")
# Open app in full screen size
screen_width = app.winfo_screenwidth()
screen_height = app.winfo_screenheight()
app.geometry("%dx%d" % (screen_width, screen_height))
# Configure the 3-column layout
app.columnconfigure(0, weight=1)
app.columnconfigure(1, weight=1)
app.columnconfigure(2, weight=1)
# Define the 3 columns (= 3 frames with grid layout)
column_frame = None
column_frame_1 = tk.Frame(app)
column_frame_1.grid(row=0, column=0, sticky='new')
column_frame_2 = tk.Frame(app)
column_frame_2.grid(row=0, column=1, sticky='new')
column_frame_3 = tk.Frame(app)
column_frame_3.grid(row=0, column=2, sticky='new')
j = 0
for i in range(11):
# Check to which column the content should be added
if i >= 0 and i <= 2:
column_frame = column_frame_1
j = 0 if i == 0 else j
elif i >= 3 and i <= 5:
column_frame = column_frame_2
j = 0 if i == 3 else j
elif i >= 6:
column_frame = column_frame_3
j = 0 if i == 6 else j
# Create collapsible
collapsiblePane = Collapsible(parent=column_frame)
collapsiblePane.pack(fill='both', expand=1)
# This is the content of the collapsible
mytext = 'My '+str(i)+'. Label that contains a text.' if i < 9 else 'My '+str(i)+'. Label that contains an even longer text. The other columns are "jumping"!'
label = tk.Label(collapsiblePane.content_frame, text=mytext, justify='left', anchor='nw')
label.grid(row=0, column=0, sticky='nw')
# Raise the counters
i=i+1
j=j+1
# Start the app
app.mainloop()

Resizing the Canvas equal to the frame size in tkinter python

I have two questions related to this attached code. This code is a part of my project in which i have to manage the attendance of 50 (or more) students.
When you will run this piece of code, you will see that there is a extra white space (that might be of the canvas) inside the Label Frame i.e. Attendance_Frame. All I wanted is that the there should be no extra white space and the scrollbar, instead of being at the extreme right, should be at the place where the labels end.
I have searched for the answer to my question and saw a similar case. But there, the person wanted the frame to expand to the canvas size. Link (Tkinter: How to get frame in canvas window to expand to the size of the canvas?).
But in my case, I want the canvas size to be equal to frame size (although the frame lies inside the canvas)
The other thing I want is that all the check boxes should initially be 'checked' (showing the present state) and when I uncheck random checkboxes (to mark the absent), and click the 'Submit' button (yet to be created at the bottom of the window), I should get a list with 'entered date' as first element and the roll numbers i.e. 2018-MC-XX as other elements. For example : ['01/08/2020', '2018-MC-7', '2018-MC-11', '2018-MC-23', '2018-MC-44'].
Actually my plan is when i will get a list i will easily write it to a text file.
from tkinter import *
from tkcalendar import DateEntry
root = Tk()
root.geometry('920x600+270+50')
root.minsize(920,600)
Attendance_frame = Frame(root) ### Consider it a Main Frame
Attendance_frame.pack()
attendaceBox = LabelFrame(Attendance_frame, text = 'Take Attendance', bd = 4, relief = GROOVE, labelanchor = 'n',font = 'Arial 10 bold', fg = 'navy blue', width = 850, height = 525) # A Label Frame inside the main frame
attendaceBox.pack_propagate(0)
attendaceBox.pack(pady = 15)
dateFrame = Frame(attendaceBox) # A small frame to accommodate date entry label & entry box
dateFrame.pack(anchor = 'w')
font = 'TkDefaultFont 10 bold'
date_label = Label(dateFrame, text = 'Enter Date : ', font = font).grid(row = 0, column = 0, sticky = 'w', padx = 10, pady = 10)
date_entry = DateEntry(dateFrame, date_pattern = 'dd/mm/yyyy', showweeknumbers = FALSE, showothermonthdays = FALSE)
date_entry.grid(row = 0, column = 1, sticky = 'w')
noteLabel = Label(attendaceBox, text = 'Note: Uncheck the boxes for absentees').pack(anchor = 'w', padx = 10, pady = 5)
canvas = Canvas(attendaceBox, borderwidth=0, background="#ffffff")
checkFrame = Frame(canvas, width = 100, height = 50)
vsb = Scrollbar(canvas, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.pack_propagate(0)
canvas.create_window((4,4), window=checkFrame, anchor="nw")
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
checkFrame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
for i in range(0,51): # A loop to create Labels of students roll numbers & names
c = Checkbutton(checkFrame, text = f"{'2018-MC-'+str(i+1)} Student {i+1}")
c.grid(row = i, column = 0, padx = 10, sticky = 'w')
mainloop()
If you are creating a vertical list of items, you don't need to use a frame inside the canvas. The inner frame adds some unnecessary complexity. Instead, create the checkbuttons directly on the canvas with create_window.
You also need to configure the scrollregion attribute so that the scrollbar knows how much of the virtual canvas to scroll.
Finally, to have them selected you should assign a variable to each checkbutton, and make sure that the value is the proper value. By default checkbuttons use the values 0 and 1, so setting the variable to 1 will make it selected.
vars = []
for i in range(0,51):
var = IntVar(value=1)
vars.append(var)
x0, y0, x1, y1 = canvas.bbox("all") or (0,0,0,0)
c = Checkbutton(canvas, text = f"{'2018-MC-'+str(i+1)} Student {i+1}", variable=var)
canvas.create_window(2, y1+4, anchor="nw", window=c)
canvas.configure(scrollregion=canvas.bbox("all"))
Your all questions answer is here:
You should try this.
import tkinter as tk
from tkcalendar import DateEntry
root = tk.Tk()
root.geometry('920x600+270+50')
root.minsize(960, 600)
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
Attendance_frame = tk.Frame(root)
Attendance_frame.grid(row=0, column=0, sticky='nsew')
attendaceBox = tk.LabelFrame(Attendance_frame,
text='Take Attendance',
bd=4,
relief='groove',
labelanchor='n',
font='Arial 10 bold',
fg='navy blue',
width=850,
height=525)
attendaceBox.grid(row=0, column=0, sticky='nsew', padx=15)
Attendance_frame.columnconfigure(0, weight=1)
Attendance_frame.rowconfigure(0,weight=1)
dateFrame = tk.Frame(attendaceBox) # A small frame to accommodate date entry label & entry box
dateFrame.grid(row=0, column=0, sticky='nsew')
font = 'TkDefaultFont 10 bold'
date_label = tk.Label(dateFrame, text='Enter Date : ', font=font)
date_label.grid(row=0, column=0, sticky='w', padx=10, pady=10)
date_entry = DateEntry(dateFrame, date_pattern='dd/mm/yyyy', showweeknumbers=False, showothermonthdays=False)
date_entry.grid(row=0, column=1, sticky='w')
noteLabel = tk.Label(attendaceBox, text='Note: Uncheck the boxes for absentees', anchor='w')
noteLabel.grid(row=1, column=0, sticky='nsew')
attendaceBox.rowconfigure(2, weight=1)
canvas = tk.Canvas(attendaceBox, width=200, borderwidth=0, background="#ffffff")
# You can set width of canvas according to your need
canvas.grid(row=2, column=0, sticky='nsew')
canvas.columnconfigure(0, weight=1)
canvas.rowconfigure(0, weight=1)
vsb = tk.Scrollbar(attendaceBox, orient="vertical", command=canvas.yview)
vsb.grid(row=2, column=1, sticky='nsew')
canvas.configure(yscrollcommand=vsb.set)
checkFrame = tk.Frame(canvas, bg='green')
canvas.create_window((0, 0), window=checkFrame, anchor="nw", tags='expand')
checkFrame.columnconfigure(0, weight=1)
for i in range(0, 51): # A loop to create Labels of students roll numbers & names
c = tk.Checkbutton(checkFrame, anchor='w', text=f"{'2018-MC-' + str(i + 1)} Student {i + 1}")
c.grid(row=i, column=0, sticky='nsew')
c.select()
canvas.bind('<Configure>', lambda event: canvas.itemconfigure('expand', width=event.width))
checkFrame.update_idletasks()
canvas.config(scrollregion=canvas.bbox('all'))
root.mainloop()
Get Selected Value
vars = []
for i in range(0, 51): # A loop to create Labels of students roll numbers & names
var = tk.IntVar()
c = tk.Checkbutton(checkFrame,
variable=var,
anchor='w', text=f"{'2018-MC-' + str(i + 1)} Student {i + 1}")
c.grid(row=i, column=0, sticky='nsew')
c.select()
vars.append(var)
def state():
print(list(map((lambda var: var.get()), vars)))

Multiple frames with tkinter - How to make them run on fullscreen mode

I wrote a code using tkinter to switch between frames after a few seconds.
The problem is: All the application must run in fullscreen.
Here is the code.
from tkinter import *
N_TRIALS = 3
COUNT=-2
N_INTERVALS = 2*N_TRIALS + 1
RELAXING_TIME = 2000
RESTING_TIME = 2000
TASKING_TIME = 2000
start_btn_state = False
def raise_frame(frame):
frame.tkraise()
global COUNT
COUNT+=1
print(COUNT)
if (frame == f3 and COUNT==N_INTERVALS):
frame.after(RESTING_TIME,lambda:raise_frame(f5))
elif(frame == f5):
frame.after(RELAXING_TIME,lambda:raise_frame(f6))
elif frame == f2:
frame.after(RELAXING_TIME, lambda:raise_frame(f3))
elif frame == f3:
frame.after(RESTING_TIME, lambda:raise_frame(f4))
elif frame == f4:
frame.after(TASKING_TIME, lambda:raise_frame(f3))
elif frame==f6:
root.destroy()
def finish():
root.destroy()
def start():
start_btn_state=True
raise_frame(f2)
root = Tk()
f1 = Frame(root)
f2 = Frame(root)
f3 = Frame(root)
f4 = Frame(root)
f5 = Frame(root)
f6 = Frame(root)
for frame in (f1, f2, f3, f4, f5,f6):
frame.grid(row = 0, column = 0, sticky='nsew')
lb0=Label(f1, text="blablabla",font=("Arial Bold",10))
lb0.pack(padx = 10, pady=10)
lb1=Label(f1, text="blablabla",font = ("Arial Bold",10),fg = "black")
lb1.pack(padx = 10, pady=10)
lb2 = Label(f1, text="blablabla",font = ("Arial Bold",10),fg = "green")
lb2.pack(padx = 10, pady=10)
lb3 = Label(f1, text="blablabla",font = ("Arial Bold",10),fg = "blue")
lb3.pack(padx = 10, pady=10)
lb4 = Label(f1, text="blablabla",font = ("Arial Bold",10),fg = "red")
lb4.pack(padx = 10, pady=10)
start_value=BooleanVar()
btn_start=Button(f1, text="Start",font = ("Arial Bold",20), command = start)
btn_start.pack(padx=10,pady=30)
close_value=BooleanVar()
btn_close=Button(f1, text="CLOSE",font = ("Arial Bold",20), command=finish)
btn_close.pack(padx=10,pady=30)
Label(f2, text='ACTION 1').pack()
#Button(f2, text='Go to frame 3', command=lambda:raise_frame(f1)).pack()
f2.config(bg='red')
Label(f3, text='ACTION2').pack(side='left')
f3.config(bg='green')
Label(f4, text='ACTION3').pack()
f4.config(bg='blue')
Label(f5, text='RELAXING FINAL').pack()
f5.config(bg='black')
raise_frame(f1)
root.mainloop()
I don't know how to expand the frames to fill all the window. I tried everything: geometry, width and height, etc. It seems probably (100% sure) that I am doing something wrong to put those frames on fullscreen.
could anyone help me?
Sorry about the code that is not in OOP. I am learning about it.
I appreciate the help!
Best Regards
The placement and geometry of a window on screen is controlled by the window manager. Your application provides information about its size but the window manager is what decides which windows are visible and where they get placed. For this reason the flag that controls if a Tk window is fullscreen or not is one of the wm_attributes flags.
You can set your toplevel window to fullscreen using root.wm_attributes('-fullscreen', 1). If your frames are then managed such that they expand to fill the parent toplevel then they will fill the screen. For that with your grid usage you should configure the root grid geometry manager to allow (0,0) to expand to fill the area:
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
Or you could place each frame here at 0,0 and fill the available space using:
frame.place(x=0, y=0, relwidth=1.0, relheight=1.0)
This is one situation where place might be appropriate over grid.

Categories

Resources