I have a Frame that contains Treeview and a Frame-embedded-in-a-Canvas.
Treeview displays documents from MongoDB in one '#0' column and every time a user selects any document I generate from document's fields a list of Checkbuttons in the Frame-embedded-in-a-Canvas.
The issue I got is that Treeview width is not constant, but I just can't understand why it changes and when exactly it happens.
Every time after generating new Checkbuttons list my Treeview width grows by 30 pixels without any regard to the fact that both the Treeview and the Frame-embedded-in-a-Canvas are expected to be in parent's grid columns 0 and 1 respectively with zero weight.
Here's a link to the GIF showing how it looks. And below you can find my code concerning these widgets.
Show me please where to look for this issue reason.
def treeview_reload():
dt_tv.delete(*dt_tv.get_children())
dt_tv.insert('', 'end', '_b_', text='biomes')
dt_tv.insert('', 'end', '_z_', text='zones')
dt_tv.insert('', 'end', '_p_', text='points')
dt_tv.insert('', 'end', '_m_', text='biomaterials')
dt_tv.insert('', 'end', '_c_', text='characters')
def tv_sel_handler(event):
try:
sel_iid = event.widget.selection()[0]
except IndexError:
sel_iid = ''
try:
generate_model(MAP[sel_iid])
except KeyError:
pass
def generate_model(document, new_list=True, row=0, indent=0):
if new_list:
for c in list(dt_model.children.values()):
c.destroy()
i = row
for field in document.keys():
if type(document[field]) is list:
cb = ttk.Label(dt_model, text=indent*2*' '+field)
cb.grid(row=i, column=0, sticky='w', padx=30, pady=4)
cb['font'] = ("Noto Mono", 13)
else:
cb = ttk.Checkbutton(dt_model, text=indent*2*' '+field)
cb.grid(row=i, column=0, sticky='w')
ttk.Style().configure('Mono.TCheckbutton', font=("Noto Mono", 13))
cb['style'] = 'Mono.TCheckbutton'
if type(document[field]) is dict:
i = generate_model(document[field], False, i+1, indent+1)
if i > 17:
vsb = ttk.Scrollbar(pdb_data, orient=VERTICAL, command=dt_canv.yview)
dt_canv['yscrollcommand'] = vsb.set
vsb.grid(row=0, column=2, sticky='nsw')
dt_model.bind('<Configure>',
lambda event, canvas=dt_canv:
canvas.configure(scrollregion=canvas.bbox("all")))
dt_model.bind('<Enter>',
lambda event:
dt_canv.bind_all("<MouseWheel>",
lambda event:
dt_canv.yview_scroll(int(-1*(event.delta/120)), "units")))
dt_model.bind('<Leave>',
lambda event: dt_canv.unbind_all("<MouseWheel>"))
return i
# ...
# ___ frame for the data
pdb_data = ttk.Frame(page_db, width=1250, height=450)
pdb_data.grid(row=6, column=0, columnspan=2, sticky='nsew', pady=24)
# ____ categorized documents list
dt_tv = ttk.Treeview(pdb_data, selectmode='browse', show=('tree',))
dt_tv.column('#0', width=250)
dt_tv.grid(row=0, column=0, sticky='nsw')
dt_tv.bind('<<TreeviewSelect>>', tv_sel_handler)
treeview_reload()
# ____ auxiliary canvas
dt_canv = Canvas(pdb_data, borderwidth=0, width=200)
dt_canv.grid(row=0, column=1, sticky='nsw', padx=5)
# _____ frame-embedded-in-a-canvas for checkbuttons list
dt_model = ttk.Frame(pdb_data, takefocus=0)
dt_canv.create_window((0,0), window=dt_model, anchor='nw')
pdb_data.rowconfigure(0, weight=1)
I have found a way how to prevent unexpected Treeview column width change. My solution is to remove Treeview from grid, then explicitly set column width and once again grid Treeview. The code is below.
But couldn't understand a reason of such behaviour. Any explanation is appreciated.
def treeview_reload():
dt_tv.delete(*dt_tv.get_children())
dt_tv.insert('', 'end', '_b_', text='biomes')
dt_tv.insert('', 'end', '_z_', text='zones')
dt_tv.insert('', 'end', '_p_', text='points')
dt_tv.insert('', 'end', '_m_', text='biomaterials')
dt_tv.insert('', 'end', '_c_', text='characters')
def tv_sel_handler(event):
try:
sel_iid = event.widget.selection()[0]
except IndexError:
sel_iid = ''
try:
generate_model(MAP[sel_iid])
except KeyError:
pass
def generate_model(document, new_list=True, row=0, indent=0):
# do not destroy Checkbuttons if recursive call
if new_list:
for c in list(dt_model.children.values()):
c.destroy()
i = row
for field in document.keys():
if type(document[field]) is list:
cb = ttk.Label(dt_model, text=indent*2*' '+field, font=("Noto Mono", 13))
cb.grid(row=i, column=0, sticky='w', padx=30, pady=4)
else:
ttk.Style().configure('Mono.TCheckbutton', font=("Noto Mono", 13))
cb = ttk.Checkbutton(dt_model,
text=indent*2*' '+field,
style='Mono.TCheckbutton')
cb.grid(row=i, column=0, sticky='w')
if type(document[field]) is dict:
i = generate_model(document[field], False, i+1, indent+1)
# only for recursive call
if not new_list:
return i
# this is here because Treeview width changes if grid only once
dt_tv.grid_remove()
dt_tv.column('#0', width=220)
dt_tv.grid(row=0, column=0, sticky='nsw')
# place vertical Scrollbar if needed and connect MouseWheel
if i > dt_canv.winfo_height() // 28:
vsb.grid(row=0, column=2, sticky='nsw')
dt_model.bind('<Configure>',
lambda event, canvas=dt_canv:
canvas.configure(scrollregion=canvas.bbox("all")))
dt_model.bind('<Enter>',
lambda event:
dt_canv.bind_all("<MouseWheel>",
lambda event:
dt_canv.yview_scroll(int(-1*(event.delta/120)), "units")))
dt_model.bind('<Leave>',
lambda event: dt_canv.unbind_all("<MouseWheel>"))
else:
dt_canv.unbind_all('<MouseWheel>')
dt_model.unbind_all('<Configure>')
vsb.grid_remove()
# ...
# ___ frame for the data
pdb_data = ttk.Frame(page_db, width=1250, height=450)
pdb_data.grid(row=6, column=0, columnspan=2, sticky='nsew', pady=24)
# ____ categorized documents list
dt_tv = ttk.Treeview(pdb_data, selectmode='browse', show=('tree',))
dt_tv.column('#0', width=250)
dt_tv.grid(row=0, column=0, sticky='nsw')
dt_tv.bind('<<TreeviewSelect>>', tv_sel_handler)
treeview_reload()
# ____ auxiliary canvas
dt_canv = Canvas(pdb_data, borderwidth=0, width=200)
dt_canv.grid(row=0, column=1, sticky='nsw', padx=5)
# _____ frame-embedded-in-a-canvas for checkbuttons list
dt_model = ttk.Frame(pdb_data, takefocus=0)
dt_canv.create_window((0,0), window=dt_model, anchor='nw')
# ____ vertical scrollbar for frame
vsb = ttk.Scrollbar(pdb_data, orient=VERTICAL, command=dt_canv.yview)
dt_canv['yscrollcommand'] = vsb.set
pdb_data.rowconfigure(0, weight=1)
Related
i've been trying to get this tkinter frame to fill to the side, i've tried adding in expand but that would screw up the scrollbar
Why wont this fill to the right?
This is the parent frame
self.frame_right.rowconfigure(0, weight=2)
self.frame_right.rowconfigure(1, weight=8)
self.frame_right.columnconfigure((0, 1), weight=1)
self.frame_right.columnconfigure(2, weight=0)
self.frame_info = customtkinter.CTkFrame(master=self.frame_right)
self.frame_info.grid(row=0, column=0, columnspan=2, rowspan=4, pady=20, padx=20, sticky="nsew")
# ============ frame_info ============
self.frame_info.grid_columnconfigure(1, weight=1)
self.frame_info.grid_columnconfigure(0, weight=1)
self.frame_info.grid_rowconfigure(1, weight=1)
This is the code that creates the layout
def checkhotel(self, hotel1, hotel2):
if hotel1 == "Select a hotel" or hotel2 == "Select a hotel":
errormessage(self, "Hotel not selected")
elif hotel1 not in allHotels or hotel2 not in allHotels:
errormessage(self, "Hotel does not exist in database")
else:
self.graphcanvas = customtkinter.CTkCanvas(master=self.frame_info, background="#333333", highlightthickness=0)
self.graphcanvas.grid(row=1, column=0, columnspan=4, padx=20, pady=20, sticky="nsew")
self.ctk_scrollbar = customtkinter.CTkScrollbar(master=self.frame_info, command=self.graphcanvas.yview,
scrollbar_color="white", background="grey")
self.ctk_scrollbar.grid(row=1, column=4, sticky="ns")
# connect textbox scroll event to CTk scrollbar
self.graphcanvas.configure(yscrollcommand=self.ctk_scrollbar.set)
self.frame_graphs = customtkinter.CTkFrame(master=self.graphcanvas)
self.secondframeid = self.graphcanvas.create_window((0, 0), window=self.frame_graphs, anchor="nw")
self.graphcanvas.bind("<Configure>",
lambda event: self.graphcanvas.configure(scrollregion=self.graphcanvas.bbox("all")))
#expand window
getcompreddata(self, hotel1, hotel2)
i've tried using column span and expand for binding too, however, it screws up the scrollbar
def plt_freq_neg_word(self, dataframe, hotelcolumn):
# highest negative sentiment reviews (with more than 5 words)
NEG_BE_reviews_df = dataframe[dataframe["nb_words"] >= 5].sort_values("neg", ascending=False)[
["review_clean", "neg"]].head()
all_words = ' '.join([word for word in NEG_BE_reviews_df['review_clean']])
tokenized_words = nltk.tokenize.word_tokenize(all_words)
words = nltk.word_tokenize(all_words)
fd = FreqDist(words)
top_10 = fd.most_common(10)
negativeFig = plt.Figure(figsize=(5, 4), dpi=75)
ax2 = negativeFig.add_subplot(111)
line2 = FigureCanvasTkAgg(negativeFig, self.frame_graphs)
line2.get_tk_widget().grid(row=4, column=hotelcolumn, padx=10, pady=10, columnspan=2)
fdist = pd.Series(dict(top_10))
sns.set_theme(style="ticks", )
sns.barplot(y=fdist.index, x=fdist.values, color='green', ax=ax2).set(
title="Top 10 Most Frequent word from Negative Review")
Thanks in advance
This may be a newbie problem, but I am trying to step through items in a listbox using a for loop and change colour on the items depending on some results. It works in a way that all items change to correct colour at the same time once the function "run_tc_all" is finished.
But I would like it to update the colours directly when the result is available.
Any ideas how I could implement this?
Below are the code related to the issue.
def line_color(item, color):
lb_tc.itemconfig(item, {'bg': color})
lb_tc.itemconfig(item, {'selectbackground': color})
def run_tc_all():
tc_pass = False
i = 0
#lb_tc.selection_set(0)
for tc_id in tc_list:
tc_id_next = tc_id.split(': ')
print(tc_id_next[0])
tc_pass=run_one_tc(str(tc_id_next[0]), i)
if not(tc_pass):
#print('Fail')
line_color(i, 'Red')
break:
else:
print(tc_pass)
tc_pass=True
#print('Pass')
line_color(i, 'Green')
i += 1
time.sleep(1)
lb_tc = Listbox(lb_frame, width=50, height=10, activestyle='none')
lb_tc.grid(row=0, column=0, padx=0, pady=0)
#lb_tc.pack(side=LEFT, expand=1, fill=BOTH)
lb_scrollbar = Scrollbar(lb_frame)
lb_scrollbar.grid(row=0, column=1, padx=0, pady=0, sticky=NS)
#lb_scrollbar.pack(side=RIGHT, fill=Y)
lb_tc.config(yscrollcommand=lb_scrollbar.set)
lb_scrollbar.config(command=lb_tc.yview)
# Add buttons in frame
run_button_frame = LabelFrame(test_run_frame, text="Run commands")
run_button_frame.pack(fill=X, expand=1, padx=20, pady=10)
run_all_btn = Button(run_button_frame, text='Run All', width=10, font=('bold', 10), command=run_tc_all)
run_all_btn.grid(padx=20, pady=10, row=0, column=0)
update_tc_list()
lb_tc.bind('<<ListboxSelect>>',tc_select)
I am using python3 tkinter. I am trying to update a table to dynamically add new lines of Entry widgets.
The layout is as follows:
frame_canvas include a canvas and a scrollbar
frame_entries is on the canvas, showing 5x7 windows only
frame_entries holds a 2-dimensional Entry table
I'd like to dynamically add new rows on the Entry table, thus, adding new Entry rows on frame_entries frame.
The problem now is that the addition of these new widgets won't update the widgets display, it would only replace the last row of Entry table on the screen. (data was updated correctly on the background, just the problem of display update)
I tried to call canvas.update() and frame_entries.update() but no use. Scrollbar doesn't reflect the updated Entry table either.
I updated the code snippet so you can download and try.
import tkinter as tk
total_columns = 5
total_rows = 18
tbl = []
def add_row_table():
global total_rows
new_row: list[Entry] = [tk.Entry() for _ in range(total_columns)]
for j in range(total_columns):
new_row[j] = tk.Entry(frame_entries, width=20)
new_row[j].grid(row=total_rows, column=j, sticky="news")
new_row[j].insert(tk.END, total_rows)
total_rows += 1
# canvas.update_idletasks()
# frame_entries.update_idletasks()
tbl.append(new_row)
root = tk.Tk()
root.grid_rowconfigure(0, weight=1)
root.columnconfigure(0, weight=1)
frame_main = tk.Frame(root, bg="gray")
frame_main.grid(sticky='news')
button2 = tk.Button(frame_main, text="Add Row", fg="green", command=add_row_table)
button2.grid(row=0, column=1, pady=(5, 0), sticky='nw')
frame_canvas = tk.Frame(frame_main)
frame_canvas.grid(row=2, column=0, pady=(5, 0), sticky='nw')
frame_canvas.grid_rowconfigure(0, weight=1)
frame_canvas.grid_columnconfigure(0, weight=1)
# Set grid_propagate to False to allow table resizing later
frame_canvas.grid_propagate(False)
canvas = tk.Canvas(frame_canvas, bg="yellow")
canvas.grid(row=0, column=0, sticky="news")
vsb = tk.Scrollbar(frame_canvas, orient="vertical", command=canvas.yview)
vsb.grid(row=0, column=1, sticky='ns')
canvas.configure(yscrollcommand=vsb.set)
frame_entries = tk.Frame(canvas, bg="blue")
canvas.create_window((0, 0), window=frame_entries, anchor='nw')
for i in range(total_rows):
line = [tk.Entry() for j in range(total_columns)]
for j in range(total_columns):
line[j] = tk.Entry(frame_entries, width=20)
line[j].grid(row=i, column=j, sticky="news")
line[j].insert(tk.END, i)
tbl.append(line)
frame_entries.update_idletasks()
columns_width = sum([tbl[0][j].winfo_width() for j in range(total_columns)])
rows_height = sum([tbl[i][0].winfo_height() for i in range(5)])
frame_canvas.config(width=columns_width + vsb.winfo_width(),
height=rows_height+150)
canvas.config(scrollregion=canvas.bbox("all"))
root.mainloop()
You need to update scrollregion of canvas after adding entries to frame_entries:
...
# function to be called whenever frame_entries is resized
def frame_entries_resized(event):
# update canvas scrollregion
canvas.config(scrollregion=canvas.bbox('all'))
...
frame_entries = tk.Frame(canvas, bg="blue")
# monitor size of frame_entries
frame_entries.bind('<Configure>', frame_entries_resized)
canvas.create_window((0, 0), window=frame_entries, anchor='nw')
...
Note that you have created duplicate set of entries:
for i in range(total_rows):
# initialise with entries into 'line'
line = [tk.Entry() for j in range(total_columns)]
# then assign new entry into 'line' again
for j in range(total_columns):
line[j] = tk.Entry(frame_entries, width=20)
line[j].grid(row=i, column=j, sticky="news")
line[j].insert(tk.END, i)
tbl.append(line)
You can initialize line as list of None instead:
line = [None for j in range(total_columns)]
Same issue inside add_row_table():
def add_row_table():
global total_rows
# should initialise new_row as list of None instead
new_row: list[Entry] = [tk.Entry() for _ in range(total_columns)]
for j in range(total_columns):
new_row[j] = tk.Entry(frame_entries, width=20)
new_row[j].grid(row=total_rows, column=j, sticky="news")
new_row[j].insert(tk.END, total_rows)
total_rows += 1
# canvas.update_idletasks()
# frame_entries.update_idletasks()
tbl.append(new_row)
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)))
I'm trying to create a sudoku solver. I have my grid with the entries at this point but I don't know how to get the values that the user has put in them.
I have no clue yet as to how I'm going to make the Sudoku solver but I think I'll first have to find a way to store the input in some variable(s) so I can work with them later on.
So my question is, how do I get the values that have been filled into the entries?
This is my code thus far:
from tkinter import *
root = Tk()
root.title('Sudoku Solver')
root.geometry('500x400')
mylabel = Label(root, text='Fill in the numbers and click solve').grid(row=0, column=0, columnspan=10)
# Create the grid
def beg():
global e
cells = {}
for row in range(1, 10):
for column in range(1, 10):
if ((row in (1,2,3,7,8,9) and column in (4,5,6)) or (row in (4,5,6) and column in (1,2,3,7,8,9))):
kleur='black'
else:
kleur='white'
cell = Frame(root, bg='white', highlightbackground=kleur,
highlightcolor=kleur, highlightthickness=2,
width=50, height=50, padx=3, pady=3, background='black')
cell.grid(row=row, column=column)
cells[(row, column)] = cell
e = Entry(cells[row, column], width=4, bg='white', highlightthickness=0, fg='black', relief=SUNKEN)
e.pack()
# Tell the button what to do
def solve():
global e
test = e.get()
print(test)
# Create the buttons and give them a command
clearer = Button(root, text='Clear', command=beg)
solver = Button(root, text='Solve', command=solve)
# Locate the buttons
clearer.grid(row=11, column=3, pady=30)
solver.grid(row=11, column=7, pady=30)
# Run it for the first time
beg()
root.mainloop()
I also tried changing e to e[row, column] but that gave me a syntax error.
Standard rule: if you have many elements then keep them on list or dictionary.
Do the same as with cells
Create dictionary
entries = {}
add to dictionary
entries[(row, column)] = e
and get from dictionary
def solve():
for row in range(1, 10):
for column in range(1, 10):
print(row, column, entries[(row, column)].get() )
# from tkinter import * # PEP8: `import *` is not preferred
import tkinter as tk
# --- functions ---
# Create the grid
def beg():
# remove old widgets before creating new ones
for key, val in cells.items():
print(key, val)
val.destroy()
for row in range(1, 10):
for column in range(1, 10):
if ((row in (1,2,3,7,8,9) and column in (4,5,6)) or (row in (4,5,6) and column in (1,2,3,7,8,9))):
kleur='black'
else:
kleur='white'
cell = tk.Frame(root, bg='white', highlightbackground=kleur,
highlightcolor=kleur, highlightthickness=2,
width=50, height=50, padx=3, pady=3, background='black')
cell.grid(row=row, column=column)
cells[(row, column)] = cell
e = tk.Entry(cell, width=4, bg='white', highlightthickness=0, fg='black', relief='sunken')
e.pack()
entries[(row, column)] = e
# Tell the button what to do
def solve():
for row in range(1, 10):
for column in range(1, 10):
print(row, column, entries[(row, column)].get() )
# --- main ---
entries = {}
cells = {}
root = tk.Tk()
root.title('Sudoku Solver')
root.geometry('500x400')
mylabel = tk.Label(root, text='Fill in the numbers and click solve')
mylabel.grid(row=0, column=0, columnspan=10)
# Create the buttons and give them a command
clearer = tk.Button(root, text='Clear', command=beg)
solver = tk.Button(root, text='Solve', command=solve)
# Locate the buttons
clearer.grid(row=11, column=2, pady=30, columnspan=3) # I added `columnspan=3`
solver.grid(row=11, column=6, pady=30, columnspan=3) # I added `columnspan=3`
# Run it for the first time
beg()
root.mainloop()