1

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.

  1. 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)

  2. 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()
    
7
  • You can determine what the extra whitespace is by temporarily using distinctive colors. Give your canvas one color, the checkFrame another, and attendaceBox another. Also, StackOverflow guidelines suggest that a question should only be asking one thing. Commented Aug 1, 2020 at 17:09
  • If you are just wanting to create a scrollable vertical list of checkbuttons, there are easier techniques than putting them in a frame inside a canvas. Are you interested in those ideas, or do you specifically want a solution to this question? Commented Aug 1, 2020 at 17:13
  • You can try this line in your code canvas.create_window((4, 4), window=checkFrame, anchor="nw", tags='expand') and canvas.bind('<Configure>', lambda event: canvas.itemconfigure('expand', width=event.width)) Commented Aug 1, 2020 at 17:19
  • @Manish Pushpam, these lines have removed the white space, but still the scrollbar is at the extreme end of the window. I want it to be just after the Labels Lists not with the entire window. I hope you understand. Commented Aug 1, 2020 at 17:30
  • @Bryan Oakley, Sir the extra space belongs to the Canvas widget. Commented Aug 1, 2020 at 17:36

2 Answers 2

1

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"))
Sign up to request clarification or add additional context in comments.

Comments

0

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

3 Comments

How do you get the check state of the checkbuttons later?
@acw1668, You can check my answer, now your question's answer edited.
This answer would be better if you explained what you did. Otherwise we have to compare your code to the original line-by-line and character-by-character to see what you changed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.