Python tkinter - problem with scrollbar after adding menu column - python

I'm working on my application connected with my database.
I had a working wersion of it but it didn't look good so I want to add a left side menu to it.
That's how 'show records' page looked like:
photo 1: https://imgur.com/a/egDQpLG
Code of this part:
def createTable(frame, row):
columns = ('IMIĘ','NAZWISKO','PESEL','EMAIL','NR TELEFONU','NR POLISY','DOSTAWCA','WYGASA\nZA (DNI)','NOTATKA','WYŚLIJ\nSMS','WYŚLIJ\nEMAIL')
column_counter = 0
for column in columns:
column_label = Label(frame, text=column, bg=BG_COLOR, fg=TEXT_COLOR, font="Helvetica 10")
column_label.grid(row=row,column=column_counter,padx=2)
column_counter += 1
def addRecord(frame, row, record):
column = 0
for i in range(13): #12 columns in database
if i in (6,7): #records from data base that I don't use
continue
elif i == 11 and notify==True:
send_sms = Button(frame, text="SMS", bg=BG_COLOR, fg=TEXT_COLOR, font="Helvetica 10", command=partial(sendSMSNotification, [], record[5])) #button that sends sms
send_sms.grid(row=row,column=9,padx=2)
elif i == 12 and notify==True:
send_email = Button(frame, text="EMAIL", bg=BG_COLOR, fg=TEXT_COLOR, font="Helvetica 10", command=partial(sendEmailNotification, [], record[5])) #button that sends EMAIL
send_email.grid(row=row,column=10,padx=2)
else:
result_label = Label(frame, text=record[i], bg=BG_COLOR, fg=TEXT_COLOR, font="Helvetica 10")
result_label.grid(row=row,column=column,padx=2)
column += 1
def showRecords():
destroyWidgets() #clears window
main_frame = Frame(root, bg=BG_COLOR)
main_frame.pack(fill=BOTH, expand=1)
my_canvas = Canvas(main_frame, bg=BG_COLOR)
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
my_scrollbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
my_scrollbar.pack(side=RIGHT, fill=Y)
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e:
my_canvas.configure(scrollregion=my_canvas.bbox("all")))
second_frame = Frame(my_canvas, bg=BG_COLOR)
my_canvas.create_window((0,0), window=second_frame, anchor="nw")
conn = sqlite3.connect(dbname)
c = conn.cursor()
back_button_top = Button(second_frame, text='Powrót', width=135, command=lambda: returnMain())
back_button_top.grid(row=0, column=0, pady=20, padx=20)
result_frame = Frame(second_frame, bg=BG_COLOR)
result_frame.grid(row=1, column=0)
createTable(result_frame, 0) #creates a heading of the table ('IMIĘ, NAZWISKO, PESEL' etc)
c.execute("SELECT * FROM dane")
records = c.fetchall()
row_counter = 2
for record in records:
addRecord(result_frame, row_counter, record) #adds a line of data read from the database, looked like a excel
row_counter+=1
Then I added a simple left sided menu column. So I added these lines to the showrecords function.
showMenu creates a Frame in column 0 and adds some buttons
def showMenu():
menu_frame = Frame(root,bg=BG_COLOR)
menu_frame.grid(row=0,column=0, sticky='ew')
menu_frame.grid_columnconfigure(0, weight=1)
show_records_button = Button(....
def showRecords():
destroyWidgets()
showMenu()
record_frame = Frame(root, bg=BG_COLOR)
record_frame.grid(column=1, row=0,sticky='nsew')
main_frame = Frame(record_frame, bg=BG_COLOR)
main_frame.pack(fill=BOTH, expand=1)
......
photo 2: https://imgur.com/iaRIAd9
And now I'm getting the scrollbar in the center of records column. Do you know how can I move the scroll to the right side of window? I think I have tried to change every possible attribute and nothing helped.
Also the problem of small Frame appears if I add an addition (just like my new version of code but without line with showMenu() Frame without adding a menu. So probably something is wrong with the sizing, but I dont know what.

Related

TKinter window not showing in program with .after() statement

I am trying to do a self-updating script to display a table with some data I am scraping from a few websites. The data is scraped, loaded, formatted and then it should be displayed in a table format in TKinter. However, when I make it self-refreshing with root.after() the window does not appear at all. I know the program is running, because I see output in the terminal, but nothing comes up as a TKwindow. Is there something I am missing from .after()'s behaviour? Would it not run when there are a lot of lines?
I tried just commenting the .after() part and the script would execute completely and then show me the window. I also never entered the Else statement, which is fine, but for some reason the code would not work even with just the If statement.
Below is the code I used
root = Tk()
root.geometry("1080x1080")
def calculations():
Scraping_and_writing_in_files()
final_result = File_format_pandas()
if len(final_result.index) == 0:
label = Label(root, text = "There are no hits")
label.pack()
print("I am in the if statement - no hits found")
else:
print("I am in the else statement") # I was never in the Else statement so you can ignore the code below
#Create a main frame
main_frame = Frame(root)
main_frame.pack(fill=BOTH, expand=1)
#Create a canvas
my_canvas = Canvas(main_frame)
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
#Add scrollbar
my_scrollbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
my_scrollbar.pack(side=RIGHT, fill=Y)
#Configure scrollbar
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>',lambda e: my_canvas.configure(scrollregion = my_canvas.bbox("all")))
def _on_mouse_wheel(event):
my_canvas.yview_scroll(-1 * int((event.delta / 120)), "units")
my_canvas.bind_all("<MouseWheel>", _on_mouse_wheel)
#Create another frame in the canvas
second_frame = Frame(my_canvas)
#Add that new frame to a window in the canvas
my_canvas.create_window((0,0), window=second_frame, anchor = "nw")
initial_entries1 = Entry(second_frame,font=("Helvetica", 12),bd=0,width=30)
initial_entries1.insert(0, "Match Name")
initial_entries1.config(state = "readonly")
initial_entries1.grid(row=0, column=0)
initial_entries2 = Entry(second_frame,font=("Helvetica", 12),bd=0,width=30)
initial_entries2.insert(0, "Result for T1")
initial_entries2.config(state = "readonly")
initial_entries2.grid(row=0, column=1)
initial_entries3 = Entry(second_frame,font=("Helvetica", 12),bd=0,width=30)
initial_entries3.insert(0, "Result for Draw")
initial_entries3.config(state = "readonly")
initial_entries3.grid(row=0, column=2)
initial_entries3 = Entry(second_frame,font=("Helvetica", 12),bd=0,width=30)
initial_entries3.insert(0, "Result for T2")
initial_entries3.config(state = "readonly")
initial_entries3.grid(row=0, column=3)
for thing in range(len(final_result.index)):
match_name = Entry(second_frame, font=("Helvetica", 10),bd=0,width=30)
match_name.insert(0, final_result['Match name'].iloc[thing])
match_name.config(state = "readonly")
match_name.grid(row=thing+1, column=0)
result_t1 = Entry(second_frame, font=("Helvetica", 10),bd=0,width=15)
result_t1.insert(0, final_result['Difference Team 1 For'].iloc[thing])
if float(final_result['Difference Team 1 For'].iloc[thing]) > 0:
result_t1.config(state = "readonly")
result_t1.grid(row=thing+1, column=1)
result_t2 = Entry(second_frame, font=("helvetica", 10), bd=0, width=15)
result_t2.insert(0, final_result['Difference Team 2 For'].iloc[thing])
if float(final_result['Difference Team 2 For'].iloc[thing])>0:
result_t2.config(state = "readonly")
result_t2.grid(row=thing+1, column=3)
result_draw = Entry(second_frame, font=("helvetica", 10), bd=0, width=15)
result_draw.insert(0, final_result['Difference Draw For'].iloc[thing])
if float(final_result['Difference Draw For'].iloc[thing]) > 0:
result_draw.config(state = "readonly")
result_draw.grid(row=thing+1, column=2)
root.after(2000, main_frame.destroy())
# label1 = Label(second_frame, text="Google Hyperlink", fg="blue", cursor="hand2")
# label1.pack()
# label1.bind("<Button-1>", lambda e: callback("http://www.google.com"))
root.after(1000, calculations())
calculations()
root.mainloop()
In the after method no parentheses are needed, since they call the function immediately and will use whatever it returns as callback after the delay. Thank you Jasonharper and Sujay.
root.after(1000, calculations()) => should be root.after(1000, calculations)

Selecting multiple rows and fetching them simultaneously in treeview in tkinter

How can I select multiple rows in a treeview where in the treeview is pulling up data from MySQL database, so that I can display them in my text box. I am able to do this for one row at a time but not sure on how to select multiple entries. I basically have 2 frames in my GUI, left and right frames. Left frame shows a treeview with the animal names and right frame shows a text box. When someone selects the animal name and hit Add button, it should be added into the right text box. Just want to figure out on how to do this for multiple selections. Below is my code so far.
from tkinter import *
from tkinter import ttk
import pymysql
class Animals_App:
def __init__(self, root):
self.root = root
self.root.title("Animals")
self.root.geometry("1350x750+0+0")
self.root.resizable(FALSE, FALSE)
title = Label(self.root, text="Animals", font=("times new roman", 30, "bold"), bg="#262626",
fg="white").place(x=0, y=0, relwidth=1)
self.root.config(background="powder blue")
# =====Variables========
self.animal_var = StringVar()
# ==For displaying added Animal names on the right text box
def display_name():
txt_box.insert(END, 'Animal : ' + self.animal_var.get() + '\n')
# ==========Frame 1 (Left Frame)===========
Top_Frame = Frame(self.root, bd=5, relief=RIDGE, bg="white")
Top_Frame.place(x=10, y=50, width=750, height=620)
Addbtn = Button(Top_Frame, padx=16, pady=1, bd=7, fg='black', font=('arial', 16, 'bold'), width=4,
text='Add', bg='powder blue', command=display_name).grid(row=0, column=0)
Table_Frame = Frame(self.root, bd=5, relief=RIDGE, bg="white")
Table_Frame.place(x=10, y=130, width=750, height=620)
scroll_x = Scrollbar(Table_Frame, orient=HORIZONTAL)
scroll_y = Scrollbar(Table_Frame, orient=VERTICAL)
self.Animals_table = ttk.Treeview(Table_Frame,
columns=("animal"),
xscrollcommand=scroll_x.set, yscrollcommand=scroll_y.set)
scroll_x.pack(side=BOTTOM, fill=X)
scroll_y.pack(side=RIGHT, fill=Y)
scroll_x.config(command=self.Animals_table.xview)
scroll_y.config(command=self.Animals_table.yview)
self.Animals_table.heading("animal", text="Animal Names")
self.Animals_table['show'] = 'headings'
self.Animals_table.column("animal", width=100)
self.Animals_table.pack(fill=BOTH, expand=1)
self.Animals_table.bind("<ButtonRelease-1>", self.get_cursor)
self.fetch_data()
# ==========Frame 2 (Right Frame)===========
Txt_Frame = Frame(self.root, bd=5, relief=RIDGE, bg="white")
Txt_Frame.place(x=770, y=70, width=580, height=620)
scroll_y = Scrollbar(Txt_Frame, orient=VERTICAL)
scroll_y.pack(fill=Y, side=RIGHT)
txt_box = Text(Txt_Frame, font=("times new roman", 15), bg="lightyellow", fg="black",
yscrollcommand=scroll_y.set)
txt_box.pack(fill=BOTH, expand=1)
scroll_y.config(command=txt_box.yview)
# txt_box.insert(END, 'Animal : ' + '\n')
def fetch_data(self):
con = pymysql.connect(host="localhost", user="root", password="", database="animaltree")
cur = con.cursor()
cur.execute("select * from animals")
rows = cur.fetchall()
# rows=["Cow","Deer","Dog","Zebra"]
if len(rows) != 0:
self.Animals_table.delete(*self.Animals_table.get_children())
for row in rows:
self.Animals_table.insert('', END, values=row)
con.commit()
con.close()
def get_cursor(self, ev):
cursor_row = self.Animals_table.focus()
contents = self.Animals_table.item(cursor_row)
row = contents['values']
self.animal_var.set(row[0])
root = Tk()
obj = Animals_App(root)
root.mainloop()
The default selection mode of Treeview is already in multiple mode. You need to use .selection() instead of .focus() to get the selected items.
In order to save the selections, change self.animal_var from StringVar() to Variable() and update display_name() and self.get_cursor() as below:
class Animals_App:
def __init__(self, root):
...
self.animal_var = Variable() # changed from StringVar()
def display_name():
txt_box.insert(END, 'Animal : ' + ', '.join(self.animal_var.get()) + '\n')
...
def get_cursor(self, ev):
self.animal_var.set([ev.widget.item(idx)['values'][0] for idx in ev.widget.selection()])

How to add Checkbox to every row of table to update/delete the row data from phpmyadmin in tkinter

May i know where and how do i need to do. I want to add a checkbox in every row and when it checked, the button of update or delete will only effect to the checked row.
I am new in python and currently i'm doing this for my project gui, is that anyone can help or if any suggestion you're welcome. Thanks
Below is my code:
from tkinter import *
from tkinter import messagebox
import mysql.connector
win = Tk()
win.title("Admin Signup")
win.geometry("750x400+300+90")
frame1 = Frame(win)
frame1.pack(side = TOP, fill=X)
frame2 = Frame(win)
frame2.pack(side = TOP, fill=X)
frame3 = Frame(win)
frame3.pack(side = TOP, padx = 10, pady=15)
frame4 = Frame(win)
frame4.pack(side = TOP, padx = 10)
frame5 = Frame(win)
frame5.pack(side = LEFT, padx = 10)
lbl_title = Label(frame1, text = "User List", font = ("BOLD 20"))
lbl_title.pack(side = TOP, anchor = "w", padx = 20, pady = 20)
btn_register = Button(frame2, text = "Register User")
btn_register.pack(side = TOP, anchor = "e", padx=20)
lbl01 = Label(frame3, text="Username", width=17, anchor="w", relief="raised")
lbl01.grid(row=0, column=0)
lbl02 = Label(frame3, text="Password", width=17, anchor="w", relief="raised")
lbl02.grid(row=0, column=1)
lbl03 = Label(frame3, text="Full Name", width=17, anchor="w", relief="raised")
lbl03.grid(row=0, column=2)
lbl04 = Label(frame3, text="Ic Number", width=17, anchor="w", relief="raised")
lbl04.grid(row=0, column=3)
lbl05 = Label(frame3, text="Staff Id", width=17, anchor="w", relief="raised")
lbl05.grid(row=0, column=4)
mydb = mysql.connector.connect(
host = "localhost",
user = "username",
password = "password",
database = "adminacc"
)
mycursor = mydb.cursor()
mycursor.execute("SELECT * FROM acc")
i = 0
for details in mycursor:
for j in range(len(details)):
e = Entry(frame4, width=17, relief=SUNKEN)
e.grid(row=i, column=j)
e.insert(END, details[j])
e.config(state=DISABLED, disabledforeground="blue")
i = i+1
btn_update = Button(frame5, text = "Update")
btn_update.grid(row=0, column=0, padx=15)
btn_delete = Button(frame5, text = "Delete")
btn_delete.grid(row=0, column=1)
win.mainloop()
Since every row behaves the same, suggest to use a class to encapsulate the behavior:
class AccountInfo:
def __init__(self, parent, details, row):
self.entries = []
# create entry box for each item in 'details'
for col, item in enumerate(details):
e = Entry(parent, width=17, relief=SUNKEN, disabledforeground='blue', bd=2)
e.grid(row=row, column=col)
e.insert(END, item)
e.config(state=DISABLED)
self.entries.append(e)
# create the checkbutton to select/deselect current row
self.var = BooleanVar()
Checkbutton(parent, variable=self.var, command=self.state_changed).grid(row=row, column=col+1)
def state_changed(self):
state = NORMAL if self.selected else DISABLED
# enable/disable entries except username
for e in self.entries[1:]:
e.config(state=state)
#property
def selected(self):
return self.var.get()
#property
def values(self):
return tuple(x.get() for x in self.entries)
Then using the class to create the required rows for each record retrieved from database:
mycursor.execute("SELECT * FROM acc")
accounts = [] # used to store the rows (accounts)
for row, details in enumerate(mycursor):
acc = AccountInfo(frame4, details, row)
accounts.append(acc)
The saved accounts can then be used in the callbacks of Update and Delete buttons:
def update_accounts():
for acc in accounts:
if acc.selected:
print(acc.values)
# do whatever you want on this selected account
btn_update = Button(frame5, text="Update", command=update_accounts)
Same logic on Delete button.
Note that you can modify the AccountInfo class to add functionalities that suit what you need.

Tkinter - Scrollbar does not resize when number of labels inside a frame changes

I am trying to create a GUI where left hand side is a Listbox (contained inside a frame f2) that displays employee ID's and right side is another frame second_frame (contained inside canvas and outer frame f3) that shows transaction details of each selected employee in the form of labels.
Each employee can have multiple transactions. So, The number of labels had to be dynamic, i.e. for first selected item in listbox, there could be two labels and for second selected item in listbox, it could be hundred. For every selection, I am calling two functions to destroy old labels and create new labels. While the code works fine, I am having trouble resizing the scrollbar according to the selected listbox entry. I am new to Tkinter, Please advise. Below is my code.
Also note, the test() function when called from outside any function displays the scroll bar, but does not display anything when called from within any function.
# -*- coding: utf-8 -*-
from tkinter import *
'''def test():
for i in range(0,50):
for j in range (0,7):
Label(second_frame, text=f'{i}{j}', width=20).grid(row=i, column=j, pady=5,padx=5)
'''
# --- function ---
def destroy_frame():
#f1.grid_forget()
print("destroying frame")
for label in second_frame.winfo_children():
label.destroy()
def create_frame(val):
print("creating new frame")
for i in range(0,val):
for j in range (5):
Label(second_frame, text=f'{i} {j} ', relief=GROOVE, width=10).grid(row=i, column=j, pady=5,padx=5)
def on_selection(event):
# here you can get selected element
print('previous:', listbox.get('active'))
print(' current:', listbox.get(listbox.curselection()))
# or using `event`
print('(event) previous:', event.widget.get('active'))
print('(event) current:', event.widget.get(event.widget.curselection()))
print (listbox.get(listbox.curselection()))
if (listbox.get(listbox.curselection()) == "Eid 1"):
destroy_frame()
create_frame(100)
elif (listbox.get(listbox.curselection()) == "Eid 2"):
destroy_frame()
create_frame(200)
print('---')
root = Tk()
root.geometry('800x500')
#Create base Frames
f1 = Frame(width=800, height=50, bg="yellow", colormap="new")
f1.grid(row=0, columnspan=2)
f1.grid_propagate(False)
f2 = Frame(width=200, height=425, bg="light blue", colormap="new")
f2.grid(row=1, column=0)
f2.grid_propagate(False)
f3 = Frame(width=600, height=425, bg="light green", colormap="new")
f3.grid(row=1, column=1)
f3.grid_propagate(False)
#Create header Label
l1_f1 = Label(f1, text="Employee Purchase Entries:", bg="yellow")
l1_f1.grid(row=0, column=0)
#Create Listbox
listbox = Listbox(f2, bg="light blue", width=40, height=400)
listbox.grid(row=0, column=0)
#Add Scrollbar to ListBox
list_scrollbar = Scrollbar(f2)
list_scrollbar.grid(row=0, column=1, sticky=NSEW)
#Enter Listbox Data
listbox.insert(1, 'Eid 1')
listbox.insert(2, 'Eid 2')
listbox.bind('<<ListboxSelect>>', on_selection)
#configure the Listbox and Scrollbar
listbox.config(yscrollcommand = list_scrollbar.set)
list_scrollbar.config(command = listbox.yview)
#Create a Canvas
my_canvas = Canvas(f3, width=580, height=425, bg="light green")
#my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
my_canvas.grid(row=0, column=0)
#Add a Scrollbar to the canvas
my_scrollbar = Scrollbar(f3, orient=VERTICAL, command=my_canvas.yview)
my_scrollbar.grid(row=0, column=1, sticky=NSEW)
#configure the canvas
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e : my_canvas.configure(scrollregion = my_canvas.bbox("all")))
#Create another frame inside the canvas
second_frame = Frame(my_canvas)
#Add the new frame to a window in the canvas
my_canvas.create_window((0,0), window=second_frame, anchor="nw")
#test()
root.mainloop()
Your canvas isnt trigger the configure event when you add widgets to your frame. Instead your frame is been triggerd.
So you need to put this line:
second_frame.bind('<Configure>', lambda e : my_canvas.configure(scrollregion = my_canvas.bbox("all")))
after creating second_frame

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

Categories

Resources