How change the number of columns Tkinter Python - python

I'm creating a program with Tkinter, It have 6 entry labels.
I'm with difficulty to grid these labels in the center of page.
I don't wanna to use .pack
How can I set the number of columns that the grid has? It seems tkinter ignore when I set column=6 for example.
here my code:
##Input 1 / Input de parametros
self.PwNomeLabel1 = Label(text = "Cliente:")
self.PwNomeLabel1["font"] = ("10")
self.PwNomeLabel1.grid(row=0,column=2,sticky=W)
self.inputpwtest1 = Entry(borderwidth= 2, validate='key')
self.inputpwtest1["width"] = 30
self.inputpwtest1.grid(row=0, column=3)
##Input 2
self.PwNomeLabel2 = Label(text = "Responsavel por Teste:")
self.PwNomeLabel2["font"] = ("10")
self.PwNomeLabel2.grid(row=1,column=2,sticky=W)
self.inputpwtest2 = Entry(borderwidth= 2, validate='key')
self.inputpwtest2["width"] = 30
self.inputpwtest2.grid(row=1, column=3)
##Input 3
self.PwNomeLabel3 = Label(text = "Nome do Sistema:")
self.PwNomeLabel3["font"] = ("10")
self.PwNomeLabel3.grid(row=2,column=2,sticky=W)
self.inputpwtest3 = Entry(borderwidth= 2, validate='key')
self.inputpwtest3["width"] = 30
self.inputpwtest3.grid(row=2,column=3)
##Input 4
self.PwNomeLabel4 = Label(text = "Ref:")
self.PwNomeLabel4["font"] = ("10")
self.PwNomeLabel4.grid(row=3,column=2,sticky=W)
self.inputpwtest4 = Entry(borderwidth= 2, validate='key')
self.inputpwtest4["width"] = 30
self.inputpwtest4.grid(row=3,column=3)
##Input 5
self.PwNomeLabel5 = Label(text = "Data Base:")
self.PwNomeLabel5["font"] = ("10")
self.PwNomeLabel5.grid(row=4,column=2,sticky=W)
self.inputpwtest5 = Entry(borderwidth= 2, validate='key')
self.inputpwtest5["width"] = 30
self.inputpwtest5.grid(row=4,column=3)
##Input 6
self.PwNomeLabel6 = Label(text = "Data Teste:")
self.PwNomeLabel6["font"] = ("10")
self.PwNomeLabel6.grid(row=5,column=2,sticky=W)
self.inputpwtest6 = Entry(borderwidth= 2, validate='key')
self.inputpwtest6["width"] = 30
self.inputpwtest6.grid(row=5,column=3)
root = Tk()
root.title("TEST PLATFORM")
Application(root)
root.geometry('1366x768')
root.mainloop()
In this way its results:
If I change label columns to "4" and "5" for the entry results:
Like the prints, It seems the Tkinter get confused and the grid stay desorganized

As mentioned in the comments you are likely needing to manage row/column weights.
Here is an example that does that while also showing how you can reduce your code by dynamically generating labels and entry fields instead of writing a wall of text for all of them.
import tkinter as tk
root = tk.Tk()
root.geometry('800x500')
root.title("TEST PLATFORM")
label_list = ['Cliente:', 'Responsavel por Teste:', 'Nome do Sistema:', 'Ref:', 'Data Base:', 'Data Teste:']
entry_list = []
# Row and Column configure to manage weights
root.columnconfigure(0, weight=1)
root.columnconfigure(2, weight=1)
root.rowconfigure(0, weight=1)
root.rowconfigure(2, weight=1)
# Add a frame to hold the rest of the widgets and place that frame in the row/column without a weight.
# This will allow us to center everything that we place in the frame.
frame = tk.Frame(root)
frame.grid(row=1, column=1)
# use a loop to create our widgets.
for ndex, label in enumerate(label_list):
tk.Label(frame, text=label, font='10').grid(row=ndex, column=0, sticky='w')
# Store the entry widgets in a list for later use
entry_list.append(tk.Entry(frame, borderwidth=2, width=30))
entry_list[-1].grid(row=ndex, column=1)
# Get and print each entry value.
def print_entries():
for entry in entry_list:
print(entry.get())
tk.Button(frame, text='Selecionar Arquivo', command=print_entries).grid(row=len(label_list)+1, column=0, columnspan=2)
root.mainloop()

If a column is empty (no widget inside), then it will not appear.
In the following example, I put a frame in column 0 with width=100 in order to have my column 1 "centered". I also have the parameter weight=1 for the 3 columns, so it grows the same way when I expand the window.
import tkinter as tk
root = tk.Tk()
for i in range(3):
root.columnconfigure(i, weight=1)
tk.Frame(root, width=100).grid(row=0, column=0, sticky='w')
# tk.Label(root, text='Left').grid(row=0, column=0, sticky='w')
tk.Label(root, text='Center').grid(row=0, column=1)
tk.Label(root, text='Right').grid(row=0, column=2, sticky='e')
root.mainloop()

Related

How to insert values created by a loop function to tkinter text boxes which are also created automatically with a loop function

Hi I'm trying to write a code that calculates the net present values of the installments. The code runs perfect up to a point where I can't insert the calculated values in to the tkinter text boxes individually.
For example the code is asking the yearly interest rate and the input can be 15. The list price of an house can be 1000000 and the down payment can be 0.2 which is %20 of the list price. And we can input 12 as the number of installments.
Down payment will be calculated by multiplying 1000000 with 0.2 and gives 200000. And the execution will be inserted to the first tkinter text box. But when the calculation done for the net present values of the installments, all of them appear inside last tkinter text box rather than appearing individually.
Here is the code;
# This program is to create a payment schedule for the customers and check whether
# the payment plan is suitable for the seller in terms of net present value.
from tkinter import *
window=Tk()
# This part asks the number of installments and creates the desired amount of text boxes.
def create():
for y in range(number_of_installments.get()):
t11 = Label(window,text= '%s.Installment'%(y+1),foreground="green")
t11.grid(row = y+2,column=0)
for y in range(number_of_installments.get()):
ttt = Text(window, height=1, width=20, foreground="red")
ttt.grid(row = y+2,column=1)
#Net present values of the installments are calculated in this part.
def NPV_calculation():
interest_rate = [pow(1+0.0125,i) for i in range(1,int(number_of_installments.get())+1)]
installment_amount = (float(list_price.get())-(float(list_price.get())*float(downpayment_percentage.get())))/(float(number_of_installments.get()))
calculation = [installment_amount/i for i in interest_rate]
ttt.insert(END,calculation)
downpayment_calculation()
NPV_calculation()
#Downpayment calculated by entering a value between 0 to 1. For example if 0.2 is typed in the textbox it will multiply the list price by %20.
def downpayment_calculation():
Downpayment = float(list_price.get())*float(downpayment_percentage.get())
t0.insert(END,Downpayment)
#Entry boxes
number_of_installments = IntVar(value="")
installment = Entry(window, textvariable=number_of_installments)
installment.grid(row=3,column=3)
interest_value = StringVar()
interest = Entry(window, textvariable=interest_value)
interest.grid(row=0,column=3)
list_price = StringVar()
list = Entry(window, textvariable=list_price)
list.grid(row=1,column=3)
downpayment_percentage = StringVar()
downpayment = Entry(window, textvariable=downpayment_percentage)
downpayment.grid(row=2,column=3)
#Create button for creating number of grids based on the number of installments.
b1 = Button(window, text="Create", command=create)
b1.grid(row=0,column=4)
#Labels for the enrty boxes
n_installments = Label(window,text="Number Of Installments",foreground="blue")
n_installments.grid(row=3,column=2)
yearly_interest = Label(window,text="Yearly Interest",foreground="blue")
yearly_interest.grid(row=0,column=2)
price_list = Label(window,text="List Price",foreground="blue")
price_list.grid(row=1,column=2)
per_downpayment = Label(window,text="Downpayment Percentage",foreground="blue")
per_downpayment.grid(row=2,column=2)
#Label and text box for the downpayment
t0 = Label(window,text="Downpayment",foreground="green")
t0.grid(row=1,column=0)
t0 = Text(window, height=1, width=20, foreground="red")
t0.grid(row=1,column=1)
window.mainloop()
When you call the NPV_calculation function, ttt is the last text widget.
# This part asks the number of installments and creates the desired amount of text boxes.
def create():
for y in range(number_of_installments.get()):
t11 = Label(window,text= '%s.Installment'%(y+1),foreground="green")
t11.grid(row = y+2,column=0)
for y in range(number_of_installments.get()):
ttt = Text(window, height=1, width=20, foreground="red")
ttt.grid(row = y+2,column=1)
print("the object named ttt in this loop iteration is:", ttt)
#Net present values of the installments are calculated in this part.
def NPV_calculation():
interest_rate = [pow(1+0.0125,i) for i in range(1,int(number_of_installments.get())+1)]
installment_amount = (float(list_price.get())-(float(list_price.get())*float(downpayment_percentage.get())))/(float(number_of_installments.get()))
calculation = [installment_amount/i for i in interest_rate]
ttt.insert(END,calculation)
print("the object named ttt is:", ttt)
downpayment_calculation()
NPV_calculation() # <- when you call this function, ttt is the last Text widget
Output for number_of_installments = 3:
the object named ttt in this loop iteration is: .!text2
the object named ttt in this loop iteration is: .!text3
the object named ttt in this loop iteration is: .!text4
the object named ttt is: .!text4
You need to insert values when creating a text widget in a loop. It is better to move the NPV_calculation function out of the loop.
This is a simplified example for the part where the values are generated automatically.
import tkinter as tk
window = tk.Tk()
def do_n_calculation(n):
calculation = [x+1 for x in range(n)]
return calculation
def create():
# get new values
n = number_of_installments.get()
calculation_list = do_n_calculation(n)
# clear previous values
for i in installment_frame.winfo_children():
i.destroy()
# insert new values
for y in range(n):
t11 = tk.Label(installment_frame, text= '%s.Installment'%(y+1), foreground="green")
t11.grid(row=y, column=0)
for y in range(n):
ttt = tk.Text(installment_frame, height=1, width=20, foreground="red")
ttt.grid(row=y, column=1)
ttt.insert(tk.END, calculation_list[y])
label = tk.Label(window, text="Number Of Installments")
label.grid(row=0, column=0)
number_of_installments = tk.IntVar(value="")
entry = tk.Entry(window, textvariable=number_of_installments)
entry.grid(row=0, column=1)
button = tk.Button(window, text="Create", command=create)
button.grid(row=0, column=2)
installment_frame = tk.Frame(window)
installment_frame.grid(row=1, column=0)
window.mainloop()
Complete example using the class.
import tkinter as tk
class Application(tk.Frame):
"""
| column 0 | column 1 |
-----------------------------------------
row 0 | downpayment_frame | form_frame |
-----------------------------------------
row 1 | installment_frame | |
-----------------------------------------
"""
def __init__(self, master):
super().__init__(master)
# data attributes
self.downpayment_value = None
self.calculation_list = None
# left side
# Label and text box for the downpayment
self.downpayment_frame = tk.Frame(self)
self.downpayment_frame.grid(row=0, column=0, padx=5, pady=5)
self.downpayment_label = tk.Label(self.downpayment_frame, text="Downpayment", foreground="green")
self.downpayment_label.grid(row=0, column=0)
self.downpayment_text = tk.Text(self.downpayment_frame, height=1, width=20, foreground="red")
self.downpayment_text.grid(row=0, column=1)
self.installment_frame = tk.Frame(self)
self.installment_frame.grid(row=1, column=0, padx=5, pady=5)
# right side
self.form_frame = tk.Frame(self)
self.form_frame.grid(row=0, column=1, padx=5, pady=5)
# Labels for the enrty boxes
self.yearly_interest = tk.Label(self.form_frame, text="Yearly Interest", foreground="blue")
self.yearly_interest.grid(row=0, column=0)
self.price_list = tk.Label(self.form_frame, text="List Price", foreground="blue")
self.price_list.grid(row=1, column=0)
self.per_downpayment = tk.Label(self.form_frame, text="Downpayment Percentage", foreground="blue")
self.per_downpayment.grid(row=2, column=0)
self.n_installments = tk.Label(self.form_frame, text="Number Of Installments", foreground="blue")
self.n_installments.grid(row=3, column=0)
# Entry boxes
self.interest_value = tk.StringVar()
self.interest = tk.Entry(self.form_frame, textvariable=self.interest_value)
self.interest.grid(row=0, column=1)
self.list_price = tk.StringVar()
self.price = tk.Entry(self.form_frame, textvariable=self.list_price)
self.price.grid(row=1, column=1)
self.downpayment_percentage = tk.StringVar()
self.downpayment = tk.Entry(self.form_frame, textvariable=self.downpayment_percentage)
self.downpayment.grid(row=2, column=1)
self.number_of_installments = tk.IntVar(value="")
self.installment = tk.Entry(self.form_frame, textvariable=self.number_of_installments)
self.installment.grid(row=3, column=1)
# Create button for creating number of grids based on the number of installments.
self.create_button = tk.Button(self.form_frame, text="Create", command=self.create)
self.create_button.grid(row=0, column=2, rowspan=4, padx=[5, 0])
# Net present values of the installments are calculated in this part.
def NPV_calculation(self, number, list_price, percentage):
interest_rate = [pow(1+0.0125,i) for i in range(1,int(number)+1)]
installment_amount = (float(list_price)-(float(list_price)*float(percentage)))/(float(number))
calculation = [installment_amount/i for i in interest_rate]
return calculation
def downpayment_calculation(self, list_price, percentage):
downpayment = float(list_price)*float(percentage)
return downpayment
def create(self):
number = self.number_of_installments.get()
list_price = self.list_price.get()
percentage = self.downpayment_percentage.get()
# get new values and set data attributes
self.downpayment_value = self.downpayment_calculation(list_price, percentage)
self.calculation_list = self.NPV_calculation(number, list_price, percentage)
# clear previous values
self.downpayment_text.delete("1.0", tk.END)
for i in self.installment_frame.winfo_children():
i.destroy()
# insert new values
self.downpayment_text.insert(tk.END, self.downpayment_value)
for y in range(number):
label = tk.Label(self.installment_frame,text= '%s.Installment'%(y+1), foreground="green")
label.grid(row=y, column=0)
for y in range(number):
text = tk.Text(self.installment_frame, height=1, width=20, foreground="red")
text.grid(row=y, column=1)
text.insert(tk.END, self.calculation_list[y])
self.get_calculation()
def get_calculation(self):
print(self.downpayment_value)
print(self.calculation_list)
root = tk.Tk()
app = Application(master=root)
app.pack()
app.mainloop()

make tkinter window shrink, as widgets are deleted

I'm making some program, where I input a bunch of stuff into an entry and it gets printed into a row. I also added a feature where you can delete a row. However, when I delete a row, the window does not shrink. The way I actually made the program was by having 2 frames; the main frame with the buttons and entries, and the output or text frame. When I delete a row, it actually appends the data from a list, deletes the frame and all the widgets and reprints the rows, but with out the row I deleted.
The issue with my code, is that when I delete a row, the rows that weren't deleted start to get smaller and compress and secondly, the bottom of the window doesn't move upwards, leaving a blank white space.
Any help would be appreciated, thanks.
actually appending, labelling and printing the row is in function append_entry() and my delete function is delete_row()
from tkinter import *
global main_window
def quit():
main_window.destroy()
def entry_labels():
leader_label = Label(main_frame, text = 'Customer Name')
leader_label.grid(column=0, row=0)
location_label = Label(main_frame, text = 'Receipt Number')
location_label.grid(column=0, row=1)
numcampers_label = Label(main_frame, text = 'Item Hired')
numcampers_label.grid(column=0, row=2)
weather_label = Label(main_frame, text = 'Number Hired')
weather_label.grid(column=0, row=3)
row_label = Label(main_frame, text= 'Row')
row_label.grid(column=3, row=2)
def button():
print_button = Button(main_frame, text = "Print Details", command = append_entry)
print_button.grid(column=3, row=1)
quit_button = Button(main_frame, text= "Quit", command=quit)
quit_button.grid(column=4, row=0)
delete_row_button = Button(main_frame, text = 'Delete Row', command = delete_row)
delete_row_button.grid(column=4, row=3)
def entry():
global name_entry
name_entry = Entry(main_frame)
name_entry.grid(column=1, row=0)
global receipt_entry
receipt_entry = Entry(main_frame)
receipt_entry.grid(column=1, row=1)
global hired_entry
hired_entry = Entry(main_frame)
hired_entry.grid(column=1, row=2)
global num_hired_entry
num_hired_entry = Entry(main_frame)
num_hired_entry.grid(column=1, row=3)
global delete_row_entry
delete_row_entry = Entry(main_frame)
delete_row_entry.grid(column=4, row=2)
def table_headers():
row_header = Label(main_frame, text='Row', font = 'Arial 10 bold')
row_header.grid(column=0, row=4)
customer_header = Label(main_frame, text='Customer Name', font = 'Arial 10 bold')
customer_header.grid(column=1, row=4)
receipt_header = Label(main_frame, text='Receipt Number', font = 'Arial 10 bold')
receipt_header.grid(column=3, row=4)
item_header = Label(main_frame, text='Item Hired', font = 'Arial 10 bold')
item_header.grid(column=2, row=4)
num_header = Label(main_frame, text='Number Hired', font = 'Arial 10 bold')
num_header.grid(column=4, row=4)
def append_entry():
global second_frame
second_frame = Frame(main_window)
second_frame.grid(column=0, row=6)
leader_error_var.set("")
location_error_var.set("")
numcamper_error_var.set("")
weather_error_var.set("")
global name_count
name_count = 0
global ROWS_ABOVE
ROWS_ABOVE = 6
try:
name_entry_str = str(name_entry.get())
hired_entry_str = str(hired_entry.get())
receipt_entry_int = str(receipt_entry.get())
num_hired_entry_int = str(num_hired_entry.get())
if len(name_entry.get()) != 0:
input_data_col1.append([name_entry_str])
input_data_col2.append([hired_entry_str])
input_data_col3.append([receipt_entry_int])
input_data_col4.append([num_hired_entry_int])
counters['total_entries'] += 1
print(input_data_col1)
print(input_data_col2)
print(input_data_col3)
print(input_data_col4)
while name_count < counters ['total_entries']:
global name
name = Label(second_frame, text=(input_data_col1[name_count][-1])) ##using -1 selects the latest entry in the list
name.grid(column=1, row=name_count + ROWS_ABOVE, padx=50)
item = Label(second_frame, text=(input_data_col2[name_count][-1]))
item.grid(column=2, row=name_count + ROWS_ABOVE, padx=50)
row = Label(second_frame, text=name_count)
row.grid(column=0, row=name_count + ROWS_ABOVE, padx=60)
receipt = Label(second_frame, text=(input_data_col3[name_count][-1]))
receipt.grid(column=3, row=name_count + ROWS_ABOVE, padx=50)
num = Label(second_frame, text=(input_data_col4[name_count][-1]))
num.grid(column=4, row= name_count + ROWS_ABOVE, padx=50)
name_count += 1
name_entry.delete(0,END)
receipt_entry.delete(0,END)
hired_entry.delete(0,END)
num_hired_entry.delete(0,END)
except:
leader_error_var.set("Check inputs")
#location_error_var.set("please enter a valid num")
#numcamper_error_var.set("numcamper error test")
weather_error_var.set("")
name_entry.delete(0,END)
receipt_entry.delete(0,END)
hired_entry.delete(0,END)
num_hired_entry.delete(0,END)
def delete_row():
user_del =int(delete_row_entry.get())
counters['total_entries'] -= 1
input_data_col1.pop(user_del)
input_data_col2.pop(user_del)
input_data_col3.pop(user_del)
input_data_col4.pop(user_del)
data = [input_data_col1,input_data_col2,input_data_col3,input_data_col4]
for widget in second_frame.winfo_children():
widget.destroy()
append_entry()
print(input_data_col1)
print(input_data_col2)
print(input_data_col3)
print(input_data_col4)
def error_prevention():
#leader_error_var.set("leader error test")
#location_error_var.set("location error test")
#numcamper_error_var.set("numcamper error test")
#weather_error_var.set("weather error test")
#weather_error_var.set("_______________")
leader_error = Label(main_frame, textvariable = leader_error_var, fg = 'red')
leader_error.grid(column=2, row=0)
location_error = Label(main_frame, textvariable = location_error_var, fg = 'red')
location_error.grid(column=2, row=1)
numcamper_error = Label(main_frame, textvariable = numcamper_error_var, fg = 'red', width = 13)
numcamper_error.grid(column=2, row=2)
weather_error = Label(main_frame, textvariable = weather_error_var, fg = 'red')
weather_error.grid(column=2, row=3)
def main():
global main_window
main_window = Tk()
global input_data_col1
input_data_col1 = []
global input_data_col2
input_data_col2 = []
global input_data_col3
input_data_col3 = []
global input_data_col4
input_data_col4 = []
global input_data
input_data = []
global main_frame
main_frame = Frame(main_window)
main_frame.grid(row=0,column=0)
global counters
counters = {'total_entries':0, 'name_count':0}
#global number
#number = {'total_entries':0}
def stringvars():
global location_error_var
location_error_var = StringVar()
location_error_var.set("")
global numcamper_error_var
numcamper_error_var = StringVar()
numcamper_error_var.set("")
global leader_error_var
leader_error_var = StringVar()
leader_error_var.set("")
global weather_error_var
weather_error_var = StringVar()
leader_error_var.set("")
stringvars()
entry_labels()
entry()
error_prevention()
button()
table_headers()
main()
main_window.mainloop()
Under the code
for widget in second_frame.winfo_children():
widget.destroy()
add this block of code
second_frame.pack()
it will be like this
for widget in second_frame.winfo_children():
widget.destroy()
second_frame.pack()
I hope this helps you
You can use
main_window.geometry("1200x800+100+100")
to change size and position of main_window. Here the window width will be 1200 and height will be 800, positioned 100px to the top left corner of screen. The +100+100 is optional.
You may add geometry() to delete_row callback to resize the frame. Though you might have to calculate the proper size after widget deletion.
As to "when I delete a row, the rows that weren't deleted start to get smaller and compress",
That's due to how grid layout works. If there are two widgets on the same grid row, the grid height will be equal the the higher widget height. When the higher widget is removed, the grid will resize to the smaller widget height and appear to 'shrink'.
To solve that, you can try add padding to the widget, the syntax is
widget.grid(column=1,row=1,padx=(10,10),pady=(10,10))
Alternatively, you may try other layout management: .place will give you absolute layout control. Or you can use pack and let tkinter decide the proper position.

Creating and Getting values from tkinter check boxes using for loop

This code is a part of my project in which I have to manage the attendance of 50 (or more) students.
The thing I want is that all the checkboxes 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. Also, if there is another way of creating multiple scrollable checkboxes without packing them inside a canvas then please do tell!
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()
First you need StringVar for each Checkbutton in order to get the state of the Checkbuttons later. Then you can use a list to hold the StringVars so that you can access them later. You can set the onvalue of the checkbuttons to the roll number associated to them.
Also you can use Text widget instead of Canvas+Frame. Below is an example:
import tkinter as tk
root = tk.Tk()
frame = tk.Frame(root)
frame.pack()
text = tk.Text(frame, width=40, height=20)
text.pack(side=tk.LEFT, fill=tk.BOTH)
vars = []
for i in range(51):
rollnum = '2018-MC-'+str(i+1)
var = tk.StringVar(value=rollnum)
cb = tk.Checkbutton(text, text=rollnum, variable=var, onvalue=rollnum, offvalue='', bg='white')
text.window_create('end', window=cb)
text.insert('end', '\n')
vars.append(var)
vsb = tk.Scrollbar(frame, orient=tk.VERTICAL, command=text.yview)
vsb.pack(side=tk.RIGHT, fill=tk.Y)
text.config(yscrollcommand=vsb.set)
def submit():
# extract roll numbers for checked checkbuttons
result = [var.get() for var in vars if var.get()]
print(result)
tk.Button(root, text='Submit', command=submit).pack()
root.mainloop()

Tkinter dynamically change a widget position with grid geometry manager

I am currently working on a program where I need to change the position of a widget.
Here is my code:
root = Tk()
frame = Frame(root, bg="black")
label1 = Label(frame, text="not important")
label.grid(row=1, column=1)
#some stuff happens
x = aFunctionThatReturnsXCoordinate #not actual name
y = aFunctionThatReturnsYCoordinate
Now I want to change the position of label1 to the new coordinates.
I have tried:
label1.forget_grid()
label1.grid(rows=x, columns=y)
#Ive tried label1/frame.update after this code but it didnt do anything
I've also tried to do it without the grid_forget.
I didn't forget the frame.pack and root.mainloop.
Is there a function to change the position?
I have made a code which contains a label and a button. When the button is pressed , the row of the label changes from 0 to 1 and when pressed again row is changes from 1 to 0 and so on. To make difference between the frame and the root, I have set the color of the frame to sky blue and that of root to pink.
from tkinter import *
global rw;rw = 0
def changed():
global rw;rw += 1;
if rw == 2:rw=0
label.grid(row=rw,column=0)
root = Tk()
root.config(bg="pink")
frame = Frame(root, bg="sky blue")
frame.pack()
label = Label(frame,text="Hello")
label.grid(row=0,column=0)
b = Button(frame, text='Press me!', command=changed)
b.grid(row=0, column=1)
root.mainloop()
Well, the above code is a bit complicated so , if you want a simpler way to do the same:
from tkinter import *
def changed():
size = label.grid_info().get("row") #getting current row
if size == 0:size = 1
elif size == 1:size = 0
label.grid(row=size,column=0)
root = Tk()
root.config(bg="pink")
frame = Frame(root, bg="sky blue")
frame.pack()
label = Label(frame,text="Hello")
label.grid(row=0,column=0)
b = Button(frame, text='Press me!', command=changed)
b.grid(row=0, column=1)
root.mainloop()
Here is an animation:
Here is an example that toggles the position of a label from column 0 to column 1:
You have to keep in mind that unoccupied rows or columns are sized at zero pixels by the grid geometry manager.
pressing the button makes the label in row 1 swap places from column 0 to 1 and vice versa.
import tkinter as tk
def move_label(ndx=[0]):
# the 3 next toggle the column value
rowcol = [(1, 1), (1, 0)]
x, y = rowcol[ndx[0]]
ndx[0] = (ndx[0] + 1) % 2
label_at_1_0.grid(row=x, column=y)
root = tk.Tk()
frame = tk.Frame(root, bg="black")
frame.pack()
label_at_0_0 = tk.Label(frame, text="label_at_0_0")
label_at_0_0.grid(row=0, column=0)
label_at_0_1 = tk.Label(frame, text="not label_at_0_1")
label_at_0_1.grid(row=0, column=1)
label_at_1_0 = tk.Label(frame, text="label_at_1_0")
label_at_1_0.grid(row=1, column=0)
btn_to_move_label = tk.Button(frame, text='move label', command=move_label)
btn_to_move_label.grid(row=1, column=3)
root.mainloop()

How to store values from an Entry widget for loop in tkinter?

This should be a very very simple problem. I'm making a GUI in which I have multiple entry widgets... about 30 or so all in one column. Instead of making each box one by one it seems like a better idea to just generate the widgets with a loop. However, I'm finding it extremely difficult to .get() values from the entry widgets, and convert them into floats. This is what I have so far... any help would be greatly appreciated.
class Application(Frame):
def __init__(root,master):
Frame.__init__(root,master)
root.grid()
root.create_widgets()
def calcCR(root):
d1 = root.enter.get()
d1 = float(d1)
#root.answer.delete(0.0,END)
a = 'The C/R Alpha is! %lf \n' % (d1)
root.answer.insert(0.0, a)
def create_widgets(root):
### Generate Element List ###
for i in range(len(elem)):
Label(root, text=elem[i]).grid(row=i+1, column=0)
### Generate entry boxes for element wt% ###
for i in range(len(elem)):
enter = Entry(root, width = 8)
enter.grid(row = i+1,column=1)
enter.insert(0,'0.00')
root.button = Button(root, text = 'Calculate C/R', command = root.calcCR)
root.button.grid(row=11, column=2, sticky = W, padx = 10)
root.answer = Text(root, width = 50, height = 12.5, wrap = WORD)
root.answer.grid(row=1, column=2, rowspan = 10, sticky = W, padx = 10)
root = Tk()
root.title('C/R Calculator')
app = Application(root)
root.mainloop()
Put the Entry instances into a list.
from tkinter import Tk, Frame, Label, Entry, Button
class App(Frame):
def __init__(root, master):
Frame.__init__(root, master)
root.grid()
root.create_widgets()
def get_values(root):
return [float(entry.get()) for entry in root.entries]
def calc_CR(root):
answer = sum(root.get_values()) #Replace with your own calculations
root.answer.config(text=str(answer))
def create_widgets(root):
root.entries = []
for i in range(20):
label = Label(root, text=str(i))
label.grid(row=i, column=0)
entry = Entry(root, width=8)
entry.grid(row=i, column=1)
entry.insert(0, '0.00')
root.entries.append(entry)
root.calc_button = Button(root, text='Calculate C/R', command=root.calc_CR)
root.calc_button.grid(row=20, column=0)
root.answer = Label(root, text='0')
root.answer.grid(row=20, column=1)
def run(root):
root.mainloop()
root = Tk()
root.title('C/R Calculator')
app = App(root)
app.run()

Categories