Adding headers to existing table created in tkinter python - python

I recently tried to create a table in tkinter. I luckily managed to find a pieces of code that works fine for me, however, I would need to add headers to this table. Do you have any suggestions how to incorporate it into the code I found here on forums?:
import tkinter as tk
class SimpleTableInput(tk.Frame):
def __init__(self, parent, rows, columns):
tk.Frame.__init__(self, parent)
self._entry = {}
self.rows = rows
self.columns = columns
# register a command to use for validation
vcmd = (self.register(self._validate), "%P")
# create the table of widgets
for row in range(self.rows):
for column in range(self.columns):
index = (row, column)
e = tk.Entry(self, validate="key", validatecommand=vcmd)
e.grid(row=row, column=column, stick="nsew")
self._entry[index] = e
# adjust column weights so they all expand equally
for column in range(self.columns):
self.grid_columnconfigure(column, weight=1)
# designate a final, empty row to fill up any extra space
self.grid_rowconfigure(rows, weight=1)
def get(self):
'''Return a list of lists, containing the data in the table'''
result = []
for row in range(self.rows):
current_row = []
for column in range(self.columns):
index = (row, column)
current_row.append(self._entry[index].get())
result.append(current_row)
return result
def _validate(self, P):
'''Perform input validation.
Allow only an empty value, or a value that can be converted to a float
'''
if P.strip() == "":
return True
try:
f = float(P)
except ValueError:
self.bell()
return False
return True
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.table = SimpleTableInput(self, 3, 4)
self.submit = tk.Button(self, text="Submit", command=self.on_submit)
self.table.pack(side="top", fill="both", expand=True)
self.submit.pack(side="bottom")
def on_submit(self):
print(self.table.get())
root = tk.Tk()
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()
I have tried the following but it clearly is not what I am after:
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
names = ["header1", "header2", "header3"]
self.label = tk.Label(self, text=names)
self.table = SimpleTableInput(self, 3, 4)
self.submit = tk.Button(self, text="Submit", command=self.on_submit)
self.label.pack(side="top")
self.table.pack(side="top", fill="both", expand=True)
self.submit.pack(side="bottom")
As stated below, I would like to have headers that dynamically appears above the table. Any help is appreciated. Thanks

Adding a label before the table will add the table header.
Update this portion of the code:
self.label = tk.Label(self, text="Table Header")
self.table = SimpleTableInput(self, 3, 4)
self.submit = tk.Button(self, text="Submit", command=self.on_submit)
self.label.pack(side="top")
self.table.pack(fill="both", expand=True)
self.submit.pack(side="bottom")
I have not repeated the given code again to let you think about it. Here is a reference label in TKinter you might find handy.

Related

How do I reinitialize a frame before I raise it in tkinter?

I have a problem regarding updating frames in tkinter. When I am in the Search frame, I update a file with some information, and then switch frames to the ShowSearch class. However, when the mainloop runs for the first time, it runs and initializes all the classes, so that my ShowSearch frame will display information in the file from the previous run of the program. My question is if there is a way for me to send data to the file storeSearch.txt, and then when I have called controller.show_frame(ShowSearch), my ShowSearch class will reinitialize and retrieve the data from the file storeSearch.txt and then display it. I only need help with reinitializing/updating the class since I already have written the code that retrieves the data from the file and displays it in my ShowSearch class.
import tkinter as tk
import Projekt_KTH_GUI as PK
import functools
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
container = tk.Frame(self)
container.pack(side = "top", fill = "both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for F in (Homescreen, Menuscreen, Create, ShowUpcoming, ShowAll, OpenList, Search, Edit, ShowSearch):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(Homescreen)
def show_frame(self, container):
frame = self.frames[container]
frame.tkraise()
class Search(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
tk.Label(self, text = "Sök efter packningslista", font = ("Times new Roman", 30)).place(x = 110, y = 0)
self.objectList = PK.main()
self.search = tk.StringVar()
tk.Label(self, text = "Var god mata in ditt sökord:").place(x = 150, y = 100)
search = tk.Entry(self, textvariable = self.search, width = 40).place(x = 60, y = 120)
search_button = tk.Button(self, text = "Enter", command = self.getList).place(x = 430, y = 122.5)
menuButton = tk.Button(self, text = "Meny", command = lambda: self.controller.show_frame(Menuscreen)).place(x = 100, y = 300)
def getList(self):
searchWord = self.search.get()
objectList = self.objectList
objectList = PK.search(objectList, searchWord)
PK.filesUpdate(objectList, "storeSearch.txt")
return self.controller.show_frame(ShowSearch)
I tried to use the methods .update() and .destroy(), one line before i execute frame.tkraise(), but the .update() method doesn't do anything and when I use the .destroy() method, I get an error saying _tkinter.TclError: bad window path name ".!frame.!showsearch".

How to reach and modify child class's variables from parent class when child class is one of many Tkinter frames made visible container and tkraise()

I am writing a Python GUI application with Tkinter where I have several frames that I want to manage separately. I want to put these "child" frames in separate classes (and ultimately in different files) to make the overall code more manageable. Each child class is basically a Tkinter frame with input elements. Based on selections from the main GUI, the relevant child class frame is shown. This is achieved using container and tkraise(). I want to reach child class variables from the main class but I cannot with my current code which is given below. I believe there is a problem with the initialization of child classes and/or the inheritance scheme of my app.
What is the correct way to structure a Python application in a setting where you have child classes being shown with container and tkraise() scheme and you want to reach child class variables form the main class? I appreciate your help.
import tkinter as tk
from tkinter import ttk
import math
# Padding values.
tab_padx = (10, 0)
tab_pady = (20, 0)
# Font settings.
font_1 = ("Arial", 13, "bold")
# Main class.
class Main_GUI(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.title("DEMO")
self.frame_blue_circle = BlueCircle(self, self)
self.frame_green_square = GreenSquare(self, self)
# Available shapes.
self.available_shapes = ["CIRCLE", "SQUARE"]
# Available colors.
self.available_colors = ["BLUE", "GREEN"]
# Function to run when color is changed.
def color_change(*args):
self.color = self.option_var_color.get()
if self.color == "BLUE" and self.shape == "CIRCLE":
self.type = "BlueCircle"
self.show_frame("BlueCircle")
elif self.color == "GREEN" and self.shape == "SQUARE":
self.show_frame("GreenSquare")
else:
self.show_frame("Unimplemented")
print(f"{self.color} {self.shape}")
# Function to run when shape is changed.
def shape_change(*args):
self.shape = self.option_var_shape.get()
if self.color == "BLUE" and self.shape == "CIRCLE":
self.show_frame("BlueCircle")
elif self.color == "GREEN" and self.shape == "SQUARE":
self.show_frame("GreenSquare")
else:
self.show_frame("Unimplemented")
print(f"{self.color} {self.shape}")
#GUI tabs
self.nb = ttk.Notebook(self)
self.nb.grid(row=1, column=0, sticky="w", padx=10, pady=10)
#GUI tab1 - Type selection.
self.tab1 = tk.Frame(self.nb)
self.nb.add(self.tab1, text="Type")
#GUI tab2 - Unput for selected type.
self.tab2 = tk.Frame(self.nb)
self.nb.add(self.tab2, text="Input")
#GUI tab3 - Calculate result for selected type with its specific inputs.
self.tab3 = tk.Frame(self.nb)
self.nb.add(self.tab3, text="Result")
# Tab-1 types.
# Shapes.
self.Label_shape = tk.Label(self.tab1, text = "Shape: ", font=font_1)
self.Label_shape.grid(row=10, column=0, padx=tab_padx, pady=tab_pady, sticky="W")
# Setup variable for disk type dropdown menu.
self.option_var_shape= tk.StringVar()
self.option_var_shape.set(self.available_shapes[0])
self.option_var_shape.trace("w", shape_change)
self.shape = self.option_var_shape.get()
self.shape_dropdown_menu = tk.OptionMenu(self.tab1, self.option_var_shape, *self.available_shapes)
self.shape_dropdown_menu.grid(row=10, column=1, sticky="WE", padx=tab_padx, pady=tab_pady)
self.shape_dropdown_menu.config(font=font_1, width=20)
self.shape_dropdown_menu["menu"].config(font=font_1)
# Colors.
self.Label_color = tk.Label(self.tab1, text = "Color: ", font=font_1)
self.Label_color.grid(row=20, column=0, padx=tab_padx, pady=tab_pady, sticky="W")
# Setup variable for disk type dropdown menu.
self.option_var_color= tk.StringVar()
self.option_var_color.set(self.available_colors[0])
self.option_var_color.trace("w", color_change)
self.color = self.option_var_color.get()
self.color_dropdown_menu = tk.OptionMenu(self.tab1, self.option_var_color, *self.available_colors)
self.color_dropdown_menu.grid(row=20, column=1, sticky="WE", padx=tab_padx, pady=tab_pady)
self.color_dropdown_menu.config(font=font_1, width=20)
self.color_dropdown_menu["menu"].config(font=font_1)
# Tab-2. Show frame based on selection in Tab-1.
# Container for frames.
container = tk.Frame(self.tab2)
container.grid(row=0, column=0)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (BlueCircle, GreenSquare, Unimplemented):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("BlueCircle")
# Tab-3. Calculate and display result based on Tab-1 and Tab-2.
# Label to display result.
result_text = "Result will be displayed here."
self.Label_result = tk.Label(self.tab3, text = result_text, font=font_1, fg="RED")
self.Label_result.grid(row=10, column=0, padx=tab_padx, pady=tab_pady, sticky="W")
self.button = tk.Button(self.tab3, text=f"Print", command=self.print_info)
self.button.grid(row=20, column=0, sticky="W")
# print(self.Label_result)
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
def print_info(self):
bc_text = f"Blue circle radius: {self.frame_blue_circle.radius}"
print(bc_text)
# Class defining GUI for BlueCircle.
class BlueCircle(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
super().__init__(*args, **kwargs)
self.parent = parent
self.radius = 0
# Function to run when rim radius is changed.
def Entry_change(*args):
value = self.Entry_var_radius.get()
if value == "":
self.Entry_var_radius.set(".0")
else:
try:
self.radius = float(value)
print(self.radius)
except ValueError:
self.Entry_var_radius.set("")
print(f"Warning! Floating point number only!")
tk.Frame.__init__(self, parent)
self.controller = controller
self.label = tk.Label(self, text="Blue Circle", font=font_1, fg="BLUE")
self.label.grid(row=0, column=0)
self.label = tk.Label(self, text="Radius:")
self.label.grid(row=1, column=0)
# Setup variable for entry to use in callback trace.
self.Entry_var_radius = tk.StringVar()
self.Entry_var_radius.trace("w", lambda name, index, mode, sv=self.Entry_var_radius: Entry_change(self.Entry_var_radius))
# Entry.
self.Entry_radius = tk.Entry(self, font=font_1, textvariable=self.Entry_var_radius)
self.Entry_radius.grid(row=1, column=1)
self.radius = self.Entry_radius.get()
# Class defining GUI for GreenSquare.
class GreenSquare(tk.Frame):
def __init__(self, parent, controller):
super().__init__()
self.parent = parent
# Function to run when rim radius is changed.
def Entry_change(*args):
value = self.Entry_var_lenght.get()
if value == "":
self.Entry_var_lenght.set(".0")
else:
try:
self.lenght = float(value)
self.green_square_area = self.lenght**2
# print(f"Side lenght: {self.lenght}. Area: {self.green_square_area:.2f}")
except ValueError:
self.Entry_var_lenght.set("")
print(f"Warning! Floating point number only!")
# Inıtialize variable.
self.green_square_area = 0
tk.Frame.__init__(self, parent)
self.controller = controller
self.label = tk.Label(self, text="Green Squire", font=font_1, fg="GREEN")
self.label.grid(row=0, column=0)
self.label = tk.Label(self, text="Side lenght:")
self.label.grid(row=1, column=0)
# Setup variable for entry to use in callback trace.
self.Entry_var_lenght = tk.StringVar()
self.Entry_var_lenght.trace("w", lambda name, index, mode, sv=self.Entry_var_lenght: Entry_change(self.Entry_var_lenght))
# Entry.
self.lenght = tk.Entry(self, font=font_1, textvariable=self.Entry_var_lenght)
self.lenght.grid(row=1, column=1)
self.lenght = self.Entry_var_lenght.get()
# Class defining GUI for unimplemented options.
class Unimplemented(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.label = tk.Label(self, text="To be implemented...", font=font_1, fg="RED")
self.label.grid(row=0, column=0)
if __name__ == "__main__":
app = Main_GUI()
app.mainloop()
Note that self.frame_blue_circle is not the instance of BlueCircle shown inside the notebook, so self.frame_blue_circle.radius is not the one input inside the "Input" tab.
The correct instance should be self.frames['BlueCircle'], so you need to use self.frames['BlueCircle'].radius instead:
def print_info(self):
bc_text = f"Blue circle radius: {self.frames['BlueCircle'].radius}"
print(bc_text)
In your __init__() method you have: self.frame_blue_circle = BlueCircle(self, self). This means that anywhere in your Main_GUI class (I mean typically other methods) you can access this and then its radius attribute.
In fact, you already do this here:
def print_info(self):
bc_text = f"Blue circle radius: {self.frame_blue_circle.radius}"
print(bc_text)

How to have another argument when we alread have *arg in the function?

I have a code to add rows of entries using a spinbox. I have the update function to update the changes in the number of rows using the spinbox instantly. Inside this function in the line: for j in range(3): number 3 shows the number of columns of the created entries. So, when we change the number of rows, we have 3 columns.
import tkinter as tk
class Data:
def __init__(self):
self.n_para = tk.IntVar()
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.minsize(700, 700)
container = tk.Frame(self)
container.pack()
self.data = Data()
self.frames = {}
for F in (PageOne, ):
frame = F(container, self.data)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
def show_frame(self, c):
frame = self.frames[c]
frame.tkraise()
class PageOne(tk.Frame):
def __init__(self, parent, data):
super().__init__(parent)
self.data = data
frame1 = tk.Frame(self, width=200)
frame1.grid(row=0, column=0)
self.frame2 = tk.Frame(self)
self.frame2.grid(row=1, column=0)
frame3 = tk.Frame(self)
frame3.grid(row=2, column=0)
label1 = tk.Label(frame1, text="Numeric parameters")
label1.grid(row=0, column=0, pady=10)
my_spinbox = tk.Spinbox(frame1, from_=2, to=10, textvariable=data.n_para)
my_spinbox.grid(row=0, column=1, columnspan=3)
self.row_list = []
for i in range(2):
entry_list1 = []
for j in range(3):
entryX = tk.Entry(self.frame2)
entryX.grid(row=i + 1, column=j)
entry_list1.append(entryX) # Add entry to list
self.row_list.append(entry_list1) # Add entry list to row
self.data.n_para.trace('w', self.update1) # Trace changes in n_para
# This function is for updating the number of rows
def update1(self, *args):
try:
para = int(self.data.n_para.get())
except ValueError:
return # Return without changes if ValueError occurs
rows = len(self.row_list)
diff = para - rows # Compare old number of rows with entry value
if diff == 0:
return # Return without changes
elif diff > 0: # Add rows of entries and remember them
for row in range(rows + 1, rows + diff + 1):
entry_list = [] # Local list for entries on this row
for col in range(1):
e = tk.Entry(self.frame2)
e.grid(row=row, column=col)
entry_list.append(e) # Add entry to list
self.row_list.append(entry_list) # Add entry list to row
elif diff < 0: # Remove rows of entries and forget them
for row in range(rows - 1, rows - 1 + diff, -1):
for widget in self.row_list[row]:
widget.grid_forget()
widget.destroy()
del self.row_list[-1]
app = SampleApp()
app.mainloop()
I wanted to add another argument to update1 function to get the number of columns. but, I think I have a problem with the concept of *args, and how to add another argument to the function.
when I modify the code in the below lines, the code does not work.
def update1(self, *args, n_col):
and
for j in range(n_col):
I think this is a fairly simple solution. (i'm kind of guessing a little to what error your having and how your calling the method) if this is not helpful maybe update the question with the errors.
either reverse the order in which you declare *args and n_col or when calling use a named variable.
def my_sum(*args, ncol):
result = 0
# Iterating over the Python args tuple
for x in args:
result += x
return f"{ncol} + {result}"
print(my_sum(1, 2, 3, ncol=5))
def my_sum(ncol, *args):
result = 0
# Iterating over the Python args tuple
for x in args:
result += x
return f"{ncol} + {result}"
print(my_sum(5, 1, 2, 3))
5 + 6
5 + 6
The *args argument must be the last in your method input.
Try this:
def update(self, n_col, *args):

Refresh Python tkinter TreeView

I'm creating a GUI that interacts with a Postgresql database.
The GUI displays all the contents of a certain table when the program launches.
I have a button programmed to add/remove entries.
The buttons work as when I checked the database, the entries are added to the database but I don't know how to refresh the TreeView in order for it to reflect the changes in the database.
My attempt to make it refresh is to clear (also to build) the TreeView is the _build_tree... code below:
def _build_tree(self):
for i in self.tree.get_children():
self.tree.delete(i)
for col in self.header:
self.tree.heading(col, text=col.title(),command=lambda c=col: self.sortby(self.tree, c, 0))
# adjust the column's width to the header string
self.tree.column(col,width=tkFont.Font().measure(col.title()))
for item in self.content:
self.tree.insert('', 'end', values=item)
# adjust column's width if necessary to fit each value
for ix, val in enumerate(item):
col_w = tkFont.Font().measure(val)
if self.tree.column(self.header[ix],width=None)<col_w:
self.tree.column(self.header[ix], width=col_w)
My complete code is below:
from tkinter import *
import tkinter.font as tkFont
import tkinter.ttk as ttk
import datetime
import psycopg2 as pg2
myFont = ('Impact',24)
myFontColor = 'red'
def check(): #to check if button works
print ("It works!")
class Database:
def __init__(self):
self.conn = pg2.connect(database='inventory', user='loremipsum', password='loremipsum')
self.cur = self.conn.cursor()
self.timeNow = datetime.datetime.now()
def view_rooms(self):
self.cur.execute('''
SELECT * FROM rooms
ORDER BY room_id;
''')
return self.cur.fetchall()
def add_room(self,roomID,roomName,floor):
addRoom = '''
INSERT INTO rooms (room_id,room_name,floor)
VALUES ({},'{}',{});
'''.format(roomID,roomName,floor)
self.cur.execute(addRoom)
self.conn.commit()
def del_room(self,roomID):
addRoom = '''
DELETE FROM rooms
WHERE room_id={};
'''.format(roomID)
self.cur.execute(addRoom)
self.conn.commit()
def __del__(self):
self.conn.close()
database = Database()
class Page(Frame):
def __init__(self, *args, **kwargs):
Frame.__init__(self, *args, **kwargs)
def show(self):
self.lift()
class RoomPage(Page):
def __init__(self, *args, **kwargs): #create widgets
Page.__init__(self, *args, **kwargs)
Label(self,text="ROOM",font=myFont,fg=myFontColor).grid(row=0,column=0, sticky=W)
Button(self,text="SEARCH",command=check).grid(row=0,column=1, sticky=W+E)
self.header = ['Room ID','Room','Floor']
self.content = database.view_rooms()
self.tree=ttk.Treeview(self,columns=self.header, show="headings")
vsb = ttk.Scrollbar(self,orient="vertical",command=self.tree.yview)
hsb = ttk.Scrollbar(self,orient="horizontal",command=self.tree.xview)
self.tree.configure(yscrollcommand=vsb.set,xscrollcommand=hsb.set)
self.tree.bind('<ButtonRelease-1>',self.get_selected_row)
self.tree.grid(column=0, row=1, columnspan=4, sticky='nsew')
vsb.grid(column=4, row=1, sticky='ns')
hsb.grid(column=0, row=2, columnspan=4, sticky='ew')
self._build_tree()
Button(self,text="ADD",command=AddRoom).grid(row=2,column=0,sticky=W+E)
Button(self,text="REMOVE",command=self.deleteRoom).grid(row=2,column=1, sticky=W+E)
Button(self,text="CLOSE",command=root.destroy).grid(row=2,column=3, sticky=W+E)
def _build_tree(self):
for i in self.tree.get_children():
self.tree.delete(i)
for col in self.header:
self.tree.heading(col, text=col.title(),command=lambda c=col: self.sortby(self.tree, c, 0))
# adjust the column's width to the header string
self.tree.column(col,width=tkFont.Font().measure(col.title()))
for item in self.content:
self.tree.insert('', 'end', values=item)
# adjust column's width if necessary to fit each value
for ix, val in enumerate(item):
col_w = tkFont.Font().measure(val)
if self.tree.column(self.header[ix],width=None)<col_w:
self.tree.column(self.header[ix], width=col_w)
def sortby(self,tree, col, descending):
"""sort tree contents when a column header is clicked on"""
# grab values to sort
data = [(tree.set(child, col), child) \
for child in tree.get_children('')]
# now sort the data in place
data.sort(reverse=descending)
for ix, item in enumerate(data):
tree.move(item[1], '', ix)
# switch the heading so it will sort in the opposite direction
tree.heading(col, command=lambda col=col: sortby(tree, col, \
int(not descending)))
def get_selected_row(self,event):
selection = self.tree.item(self.tree.selection())
self.selected_tuple=selection['values'][0]
def openRoom(self,event):
index=self.roomList.curselection()[0]
self.selected_tuple=self.roomList.get(index)[0]
print (self.selected_tuple)
def deleteRoom(self):
database.del_room(self.selected_tuple)
self.clear()
self.build()
class AddRoom:
def __init__(self, *args, **kwargs): #create widgets
window = Toplevel(root)
window.title("Room Details")
roomDetailsLabel = Label (window,text="Room Details",font=myFont,fg=myFontColor).grid(row=0,column=0, sticky=W,columnspan=2)
roomNumLabel = Label(window,text="Room ID").grid(row=1,column=0, sticky=E)
self.roomNumText = StringVar()
roomNameEntry = Entry(window,textvariable=self.roomNumText,width=30).grid(row=1,column=1,sticky=W)
roomNameLabel = Label(window,text="Room Name").grid(row=2,column=0, sticky=E)
self.roomNameText = StringVar()
roomNameEntry = Entry(window,textvariable=self.roomNameText,width=30).grid(row=2,column=1,sticky=W)
floorLabel = Label(window,text="Floor").grid(row=3,column=0, sticky=E)
self.floorText = StringVar()
floorEntry = Entry(window,textvariable=self.floorText,width=30).grid(row=3,column=1,sticky=W)
Button(window,text="SAVE",command=self.add_room).grid(row=4,column=0,sticky=W+E)
Button(window,text="CLOSE",command=window.destroy).grid(row=4,column=1,sticky=W+E)
def add_room(self):
database.add_room(self.roomNumText.get(),self.roomNameText.get(),self.floorText.get())
p1._build_tree()
class MainView(Frame):
def __init__(self, *args, **kwargs):
global p1
Frame.__init__(self, *args, **kwargs)
p1 = RoomPage(self)
buttonframe = Frame(self)
container = Frame(self)
buttonframe.pack(side="top", fill="x", expand=False)
container.pack(side="top", fill="both", expand=True)
p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
p1.show()
if __name__ == "__main__": #main loop
root = Tk()
root.title('Inventory System')
root.configure(bg="#BDE9EB")
parent = Frame(root, padx=10, pady=10)
parent.pack(fill=BOTH, expand=True)
main = MainView(parent)
main.pack(side="top", fill="both", expand=True)
root.wm_geometry("600x350")
root.mainloop()
How do you refresh the TreeView to reflect the changes made in the database?
Hello seems like the problem you have encountered is like mine.
You are correct when you call the get.children() after that what you will do is call the database again.
Here is my code, i hope you will get this.
def _build_tree(self):
cursor=db.cursor(buffered=True)
cursor.execute("SELECT ")
result = cursor.fetchall()
for i in self.tree.get_children():
self.tree.delete(i)
for i in result:
self.tree.insert('', 'end', values=(i[0],i[2]..)

How to fill cells in tkinter table automatically Python

I tried to incorporate this piece into my script and add the calculation into column 7, however, it appears to be failing to return correct multiple of inputs, any idea why? Here is the code:
def autofill(self, event):
row = int(event.widget.grid_info()['row'])
auto_list = self.in_list(self.LookUpList, self._entry[row, 0].get())
if auto_list is not None:
self._entry[row,1].delete(0, 'end')
self._entry[row,1].insert(0, auto_list[1])
self._entry[row,2].delete(0, 'end')
self._entry[row,2].insert(0, auto_list[2])
self._entry[row,4].delete(0, 'end')
self._entry[row,4].insert(0, auto_list[3])
self._entry[row,6].delete(0,'end')
if self._entry[row,3].get() != '':
a = self._entry[row,3].get()
else: a = 0
b = int(self._entry[row,4].get())
c = int(a * b)
self._entry[row,6].insert(0, c)
I have just found the error, had to convert one variable into int, then it worked:
self._entry[row,6].delete(0,'end')
if self._entry[row,3].get() != '':
a = int(self._entry[row,3].get())
else: a = 0
b = int(self._entry[row,4].get())
c = int(a * b)
self._entry[row,6].insert(0, c)
Here is a fix that does what you're asking for. The main thing to note is that, I added an autofill method, and a binding to the Return key that calls the autofill method. You need to hit the Return/Enter key after typing for the cells to be populated, you can change this to any other event that you prefer.
There are few other changes just to make the code work in its current state. I did not make any change regarding how efficient/elegant your implementation is, I leave that to you.
from tkinter import *
class SimpleTableInput(Frame):
def __init__(self, parent, rows, columns):
Frame.__init__(self, parent)
self._entry = {}
self.rows = rows
self.columns = columns
# register a command to use for validation
vcmd = (self.register(self._validate), "%P")
# create the table of widgets
for row in range(self.rows):
for column in range(self.columns):
index = (row, column)
if column == 3:
e = Entry(self, validate="key", validatecommand=vcmd)
else:
e = Entry(self)
e.grid(row=row, column=column, stick="nsew")
self._entry[index] = e
# adjust column weights so they all expand equally
for column in range(self.columns):
self.grid_columnconfigure(column, weight=1)
## Lookup table:
self.LookUpList=[
['a','Black skirt','PP','2000'],
['b','Pink T-shirt','PP','1000'],
['c','Yellow skirt','Marela','1500'],
['d','White trousers','PP','2000']]
## Bind the Return/Enter key to populate the entries
for row in range(self.rows):
self._entry[row, 0].bind("<Return>", self.autofill)
def in_list(self, list_of_lists, item):
if not list_of_lists:
return None
if item in list_of_lists[0]:
return list_of_lists[0]
return self.in_list(list_of_lists[1:], item)
## The method that will be called to populate the entries
def autofill(self, event):
row = int(event.widget.grid_info()['row'])
auto_list = self.in_list(self.LookUpList, self._entry[row, 0].get())
self._entry[row,1].delete(0, 'end')
self._entry[row,1].insert(0, auto_list[1])
def get(self):
'''Return a list of lists, containing the data in the table'''
result = []
for row in range(self.rows):
current_row = []
for column in range(self.columns):
index = (row, column)
current_row.append(self._entry[index].get())
result.append(current_row)
return result
def _validate(self, P):
if P.strip() == "":
return True
try:
f = float(P)
except ValueError:
self.bell()
return False
return True
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
names = ["Cislo produktu",
"Popis produktu",
"Znacka",
"Mnozstvi",
"Jednotkova cena",
"Prodejna",
"Celkova cena"]
frame = Frame(self)
frame.pack(side="top", fill="both")
for i, title in enumerate(names):
l = Label(frame, text=title)
l.grid(row=0, column=i)
frame.grid_columnconfigure(i, weight=1)
self.EmptySpace = Label(self)
self.table = SimpleTableInput(self, 30, 7)
self.table.pack(side="top", fill="both")
self.EmptySpace.pack(side="top",fill="both")
## frame1 = Frame(self)
## frame1.pack(side="left",fill="both")
## self.SubButton = Button(self, text="Ulozit a zavrit", command=self.on_ulozit)
## self.StornoButton = Button(self, text="Stornovat nakup", command=self.on_storno)
## self.SubButton.pack(side="left", fill="both", expand=True)
## self.StornoButton.pack(side="left", fill="both", expand=True)
def on_ulozit(self):
data = self.table.get()
data1 = [list(filter(None, lst)) for lst in data]
data2 = list(filter(None, data1))
for item in data2:
item.append(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
## look up property
with open('C:\\Users\\chroustovskyj\\Desktop\\Dev_py\\App\\Data_Storage\\Data_Storage.csv', 'a', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerows(data2)
root.destroy()
def on_storno(self):
print("This is storno.")
if __name__ == '__main__':
root = Tk()
root.wm_title("Formular")
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))
Example(root).pack(side="top", fill="both", expand=False)
root.mainloop()

Categories