I'm not able to update any values in the imported CSV file into GUI. I'm able to open the CSV and add a new column, but when I try to select a value and update it to my desired value I'm not able to do that.
Also, I have made a button for updating the values, but when I select the existing value and click on the update row button nothing happens.
My code is below:
import pandas as pd
import tkinter as tk
from tkinter import filedialog
from tkinter import *
from tkinter import ttk
csv_data = pd.DataFrame()
csv_text = None
entry_values = {}
def create_gui():
global csv_data, csv_text, entry_values
def open_csv():
global csv_data
csv_path = tk.filedialog.askopenfilename(title='Select CSV File', filetypes=[('CSV Files', '*.csv')])
if csv_path:
csv_data = pd.read_csv(csv_path)
update_csv_display()
create_entry_widgets()
def display_csv():
if csv_data is not None:
for col in range(len(csv_data.columns)):
label = tk.Label(csv_frame, text=csv_data.columns[col])
label.pack()
for row in range(len(csv_data)):
entry = tk.Entry(csv_frame)
entry.pack()
entry.insert(tk.END, str(csv_data.iloc[row, col]))
def save_csv():
global csv_data
if csv_data is not None:
csv_path = tk.filedialog.asksaveasfilename(title='Save CSV File', defaultextension='.csv', filetypes=[('CSV Files', '*.csv')])
csv_data.to_csv(csv_path, index=False)
print("CSV file saved successfully.")
def add_column():
global csv_data
if csv_data is not None:
column_name = entry_column.get()
csv_data[column_name] = ''
update_csv_display()
create_entry_widgets()
def update_csv_display():
csv_text.delete(1.0, tk.END)
csv_text.insert(tk.END, csv_data.to_string())
def create_entry_widgets():
global entry_values
for col in csv_data.columns:
entry_values[col] = StringVar()
entry = Entry(csv_frame, textvariable=entry_values[col])
entry.pack(padx=5, pady=5)
def update_selected_row(event=None):
print("selected row")
global csv_data
selected_items = my_tree.selection()
print(selected_items)
if selected_items:
selected_row = selected_items[0]
print(selected_row)
for col, value in entry_values.items():
print(f"{col}: {value.get()}")
entry_values[col].set(csv_data.at[selected_row, col])
def update_csv_data():
global csv_data
selected_items = my_tree.selection()
if selected_items:
selected_row = selected_items[0]
for col in csv_data.columns:
new_value = entry_values[col].get()
csv_data.at[selected_row, col] = new_value
update_csv_display()
global csv_text
root = Tk()
root.geometry("1000x800")
# Create a frame for the CSV data
csv_frame = Frame(root)
csv_frame.pack(side=tk.LEFT, padx=10, pady=10)
csv_text = Text(csv_frame, width=120, height=50)
csv_text.pack()
# Create a button to open the CSV file
csv_button = Button(csv_frame, text='Open CSV', command=open_csv)
csv_button.pack(pady=10)
# Create a button to save the CSV file
save_csv_button = Button(csv_frame, text='Save CSV', command=save_csv)
save_csv_button.pack(pady=10)
# Add a column entry field and button for manual column addition
add_column_frame = Frame(csv_frame)
add_column_frame.pack(pady=10)
entry_column = Entry(add_column_frame, width=20)
entry_column.pack(side=LEFT, padx=5)
add_column_button = Button(add_column_frame, text='Add Column', command=add_column)
add_column_button.pack(side=LEFT)
# Create a Treeview for displaying CSV data
my_tree = ttk.Treeview(root)
my_tree.pack(pady=20)
my_tree.bind("<<TreeviewSelect>>", update_selected_row)
update_row_button = Button(root, text='Update Row', command=update_selected_row)
update_row_button.pack(padx=5, pady=5)
save_changes_button = Button(root, text='Save Changes', command=update_csv_data)
save_changes_button.pack(padx=5, pady=5)
root.mainloop()
create_gui()
Please let me know where I am wrong and what I am missing.
Your doesn't work as you describe.
First: it doesn't create items in Treeview
when it loads CSV
so buttons Update Row
and Save Changes
can't work.
I add row numbers in Treeview
when I load file:
(but first I remove old items - so when I load second file then it removes rows from first file):
# remove old items in Treeview
for item in my_tree.get_children():
my_tree.delete(item)
# add new items in Treeview
for index in range(len(csv_data)):
my_tree.insert("", "end", text=index)
Second: You have code to get selected items from Treeview
but it gives you row ID
in Treeview
but you need row number
in DataFrame
.
I use this:
selected_row_id = selected_items[0]
print('Treeview row id:', selected_row_id)
selected_row = my_tree.item(selected_row_id)['text']
print('DataFrame row number:', selected_row)
Other problem: button Add column
creates new Entry
for all existing columns - so it adds many times Entry
for the same columns. It should add only one Entry - only for new column - or it should remove all previous Entry
before adding again Entry
for all columns.
I remove all Entry
. To make it simpler I create new Frame
(named rows_frame
_ and put all Entry
in this Frame
. And later I remove all children.
# remove all widgets from Frame
for item in rows_frame.winfo_children():
item.destroy()
Because it is easy so I add also Label
with column's names.
I also add Label
with column name.
My full working code:
import tkinter as tk # PEP8: `import *` is not preferred
from tkinter import filedialog
from tkinter import ttk
import pandas as pd
# --- constants --- # PEP8: `UPPER_CASE_NAMES`
DEBUG = True
# --- classes ---
# --- functions ---
def create_gui():
global csv_data
global csv_text
global entry_values
global entry_column
global csv_frame
global my_tree
def open_csv():
"""Read CSV file."""
global csv_data
if DEBUG:
print('[DEBUG] open_csv()')
csv_path = tk.filedialog.askopenfilename(title='Select CSV File', filetypes=[('CSV Files', '*.csv')])
if csv_path:
csv_data = pd.read_csv(csv_path)
update_csv_display()
create_entry_widgets()
# remove old items in Treeview
for item in my_tree.get_children():
my_tree.delete(item)
# add new items in Treeview
for index in range(len(csv_data)):
my_tree.insert("", "end", text=index)
def save_csv():
"""Write CSV file."""
global csv_data
if DEBUG:
print('[DEBUG] save_csv()')
if csv_data is not None:
csv_path = tk.filedialog.asksaveasfilename(title='Save CSV File', defaultextension='.csv', filetypes=[('CSV Files', '*.csv')])
csv_data.to_csv(csv_path, index=False)
print("CSV file saved successfully.")
def display_csv():
"""Display DataFrame in ???"""
if DEBUG:
print('[DEBUG] display_csv()')
if csv_data is not None:
for col in range(len(csv_data.columns)):
label = tk.Label(csv_frame, text=csv_data.columns[col])
label.pack()
for row in range(len(csv_data)):
entry = tk.Entry(csv_frame)
entry.pack()
entry.insert(tk.END, str(csv_data.iloc[row, col]))
def add_column():
"""Add new column to DataFrame and (re)create all Entry."""
global csv_data
if DEBUG:
print('[DEBUG] add_column()')
if csv_data is not None:
column_name = entry_column.get()
column_name = column_name.strip() # remove spaces at the ends.
if column_name: # check if name is not empty
csv_data[column_name] = ''
update_csv_display()
create_entry_widgets()
def update_csv_display():
"""Display DataFrame information in Text."""
if DEBUG:
print('[DEBUG] update_csv_display()')
csv_text.delete(1.0, tk.END)
csv_text.insert(tk.END, csv_data.to_string())
def create_entry_widgets():
"""(Re)Create Entry for all rows."""
global entry_values
global entry_widgets
if DEBUG:
print('[DEBUG] create_entry_widgets()')
# remove all widgets from Frame
for item in rows_frame.winfo_children():
item.destroy()
# create again all Entry widgets and all Treeview rows
for index, col in enumerate(csv_data.columns):
print('col:', col)
entry_values[col] = tk.StringVar()
entry = tk.Label(rows_frame, text=f"{col}:")
entry.grid(row=index, column=0, sticky='e')
entry = tk.Entry(rows_frame, textvariable=entry_values[col])
entry.grid(row=index, column=1)
def get_selected_row_from_csv(event=None):
"""Get data from `csv_data` put in all `Entry` for row selected in TreeView."""
global csv_data
if DEBUG:
print('[DEBUG] get_selected_row_from_csv()')
selected_items = my_tree.selection()
print('selected_items:', selected_items)
if selected_items:
selected_row_id = selected_items[0]
print('Treeview row id:', selected_row_id)
selected_row = my_tree.item(selected_row_id)['text']
print('DataFrame row number:', selected_row)
for col, value in entry_values.items():
print(f"{col}: {value.get()}")
entry_values[col].set(csv_data.at[selected_row, col])
def update_selected_row_in_csv():
"""Get data from all `Entry` and put in `csv_data` for row selected in TreeView."""
global csv_data
if DEBUG:
print('[DEBUG] update_selected_row_in_csv()')
selected_items = my_tree.selection()
if selected_items:
selected_row_id = selected_items[0]
print('Treeview row id:', selected_row_id)
selected_row = my_tree.item(selected_row_id)['text']
print('DataFrame row number:', selected_row)
for col in csv_data.columns:
csv_data.at[selected_row, col] = entry_values[col].get()
update_csv_display()
# --- main ---
if DEBUG:
print('[DEBUG] create_gui()')
root = tk.Tk()
#root.geometry("1200x600")
# Create a frame for the CSV data
csv_frame = tk.Frame(root)
csv_frame.pack(side="left", padx=10, pady=10)
csv_text = tk.Text(csv_frame, width=120, height=15)
csv_text.pack()
# Create a button to open the CSV file
csv_button = tk.Button(csv_frame, text='Open CSV', command=open_csv)
csv_button.pack(pady=10)
# Create a button to save the CSV file
save_csv_button = tk.Button(csv_frame, text='Save CSV', command=save_csv)
save_csv_button.pack(pady=10)
# Add a column entry field and button for manual column addition
add_column_frame = tk.Frame(csv_frame)
add_column_frame.pack(pady=10)
entry_column = tk.Entry(add_column_frame, width=10)
entry_column.pack(padx=5, side="left")
add_column_button = tk.Button(add_column_frame, text='Add Column', command=add_column)
add_column_button.pack(side="left")
rows_frame = tk.Frame(csv_frame)
rows_frame.pack()
# Create a Treeview for displaying CSV data
my_tree = ttk.Treeview(root)
my_tree.heading('#0', text='Select Row')
my_tree.pack(pady=20)
my_tree.bind("<<TreeviewSelect>>", get_selected_row_from_csv)
update_row_button = tk.Button(root, text='Get selected row from CSV', command=get_selected_row_from_csv)
update_row_button.pack(padx=5, pady=5)
save_changes_button = tk.Button(root, text='Update selected row in CSV', command=update_selected_row_in_csv)
save_changes_button.pack(padx=5, pady=5)
root.mainloop()
# --- main ---
csv_data = pd.DataFrame()
csv_text = None
entry_values = {}
entry_widgets = []
create_gui()