I am trying to edit a csv file while it is in the application. With this program I want to make the user to be able to select a row and then they go into the 'Admin' area and then they can edit the row that they have selected. I have tried different things but none of them work, and I could not find anything online for this problem.
import csv
import tkinter as tk
from tkinter import filedialog, ttk, messagebox, simpledialog
from customtkinter import *
class RoadSafetyApp:
def __init__(self, master):
self.master = master
self.master.title("Road Safety App")
self.master.geometry("800x600")
self.master.configure(bg="lightgray")
self.data = []
self.current_page = 0
self.rows_per_page = 500
self.create_widgets()
def create_widgets(self):
self.canvas = tk.Canvas(self.master)
self.canvas.pack(side="top", fill="both", expand=True)
self.tree_frame = ttk.Frame(self.canvas)
self.tree_frame.pack(side="top", fill="both", expand=True)
self.tree = ttk.Treeview(self.tree_frame)
self.tree.pack(side="left", fill="both", expand=True)
self.scrollbar_x = ttk.Scrollbar(self.tree_frame, orient="horizontal", command=self.tree.xview)
self.scrollbar_x.pack(side="bottom", fill="x")
self.tree.configure(xscrollcommand=self.scrollbar_x.set)
self.scrollbar_y = ttk.Scrollbar(self.tree_frame, orient="vertical", command=self.tree.yview)
self.scrollbar_y.pack(side="right", fill="y")
self.tree.configure(yscrollcommand=self.scrollbar_y.set)
self.edit_button = CTkButton(self.master, text="Admin", command=self.admin_edit)
self.edit_button.pack(side="left")
self.load_button = CTkButton(self.master, text="Load CSV", command=self.load_data)
self.load_button.pack(side="left")
self.search_entry = tk.Entry(self.master, bg='white', fg="black", relief='groove', width=20)
self.search_entry.pack(side="left", pady='10', padx='10')
self.column_dropdown = ttk.Combobox(self.master, values=[], state="readonly", width=15)
self.column_dropdown.pack(side="left", pady='10', padx='10')
self.search_button = CTkButton(self.master, text="Search", command=self.search_data)
self.search_button.pack(side="left")
self.help_button = CTkButton(self.master, text="Help", command=self.show_help)
self.help_button.pack(side="right")
self.row_data_frame = tk.Frame(self.master, bg="lightgray", pady='10')
self.row_data_frame.pack(side="bottom", fill="x")
self.tree.bind("<ButtonRelease-1>", self.show_row_data)
def load_image(self, image_path):
self.load_image("qldgov.png")
try:
img = PhotoImage(file=image_path)
self.canvas.create_image(0, 0, anchor=tk.NW, image=img)
# Adjust the size of the canvas based on the image size
self.canvas.config(scrollregion=self.canvas.bbox("all"))
except Exception as e:
messagebox.showerror("Error", f"Error loading image: {e}")
def admin_edit(self):
password = simpledialog.askstring("Password", "Enter the password:", show="•")
if password == "Password1":
choice = messagebox.askquestion("Edit or Create", "Do you want to edit or create data? Select 'Yes' to edit. Select 'No' to create new data.")
if choice == 'yes':
self.edit_data_window()
else:
self.create_data_window()
else:
messagebox.showerror("Authentication Error", "Invalid password!")
def edit_data_window(self):
edit_window = tk.Toplevel(self.master)
edit_window.title("Edit Crash Data")
selected_item = self.tree.selection()
if selected_item:
row_id = self.tree.identify_row(selected_item[0])
if row_id:
index_start = next((i for i, char in enumerate(row_id) if char.isdigit()), True)
if index_start is not None:
row_index = int(row_id[index_start:]) - 1
current_row_data = self.data[row_index]
self.update_data_window(current_row_data)
else:
messagebox.showwarning("No Selection", "Please select a row to edit.")
def update_data_window(self, current_row_data):
update_window = tk.Toplevel(self.master)
update_window.title("Update Data")
labels = list(current_row_data.keys())
entry_values = []
for i, label in enumerate(labels):
tk.Label(update_window, text=f"{label}:", bg="lightgray").grid(row=i, column=0, padx=10, pady=5, sticky="w")
entry = tk.Entry(update_window, bg='white', fg="black", relief='groove', width=20)
entry.grid(row=i, column=1, padx=10, pady=5, sticky="w")
entry.insert(0, str(current_row_data[label])) # Set the default value
entry_values.append(entry)
save_button = CTkButton(update_window, text="Save Changes", command=lambda: self.save_updated_data(entry_values, update_window, current_row_data))
save_button.grid(row=len(labels), column=0, columnspan=2, pady=10)
def save_updated_data(self, entry_values, update_window, current_row_data):
updated_row_data = {}
for entry, (label, value) in zip(entry_values, current_row_data.items()):
updated_row_data[label] = entry.get() if entry.get() else value
row_index = self.data.index(current_row_data)
self.data[row_index] = updated_row_data
self.save_to_csv()
messagebox.showinfo("Update", "Data updated successfully!")
update_window.destroy()
self.display_data()
def create_data_window(self):
create_window = tk.Toplevel(self.master)
create_window.title("Create Data")
labels = self.data[0].keys() if self.data else []
entry_values = []
for i, label in enumerate(labels):
tk.Label(create_window, text=f"{label}:", bg="lightgray").grid(row=i, column=0, padx=10, pady=5, sticky="w")
entry = tk.Entry(create_window, bg='white', fg="black", relief='groove', width=20)
entry.grid(row=i, column=1, padx=10, pady=5, sticky="w")
entry_values.append(entry)
save_button = CTkButton(create_window, text="Save Data", command=lambda: self.save_created_data(entry_values, create_window))
save_button.grid(row=len(labels), column=0, columnspan=2, pady=10)
def save_created_data(self, entry_values, create_window):
created_row_data = {}
for label, entry in zip(self.data[0].keys(), entry_values):
created_row_data[label] = entry.get()
self.data.append(created_row_data)
messagebox.showinfo("Save", "Data saved successfully!")
create_window.destroy()
self.display_data()
def save_to_csv(self):
file_path = filedialog.asksaveasfilename(defaultextension=".csv", filetypes=[("CSV files", "*.csv")])
if file_path:
with open(file_path, 'w', newline='') as csvfile:
csvwriter = csv.DictWriter(csvfile, fieldnames=list(self.data[0].keys()))
csvwriter.writeheader()
csvwriter.writerows(self.data)
def load_data(self):
file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*")])
if file_path:
self.data = self.load_csv(file_path)
if self.data:
self.display_data()
def load_csv(self, file_path):
try:
with open(file_path, 'r', newline='') as csvfile:
csvreader = csv.DictReader(csvfile)
data = list(csvreader)
return data
except Exception as e:
messagebox.showerror("Error", f"Error loading CSV file: {e}")
return []
def display_data(self):
self.tree.delete(*self.tree.get_children())
self.tree.configure(show="headings")
if not self.data:
print("No data to display")
return
columns = list(self.data[0].keys())
self.tree["columns"] = columns
for col in columns:
self.tree.heading(col, text=col, anchor='center')
self.tree.column(col, width=150, anchor='w')
self.column_dropdown["values"] = columns
self.column_dropdown.set(columns[0])
start_idx = self.current_page * self.rows_per_page
end_idx = start_idx + self.rows_per_page
current_page_data = self.data[start_idx:end_idx]
for i, row in enumerate(current_page_data):
values = [row.get(col, "") for col in columns]
self.tree.insert("", "end", values=values)
self.canvas.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox("all"))
def next_page(self):
total_pages = len(self.data) // self.rows_per_page + 1
if self.current_page < total_pages - 1:
self.current_page += 1
self.display_data()
else:
messagebox.showerror("Page Errors", "There is nothing else to scroll down to!")
def search_data(self):
query = self.search_entry.get().lower()
selected_column = self.column_dropdown.get()
result_rows = [row for row in self.data if query in str(row.get(selected_column, "")).lower()]
self.display_search_results(result_rows)
def display_search_results(self, result_rows):
self.tree.delete(*self.tree.get_children())
columns = list(self.data[0].keys())
self.tree["columns"] = columns
for col in columns:
self.tree.heading(col, text=col, anchor='center')
self.tree.column(col, width=150, anchor='center')
for i, row in enumerate(result_rows):
values = [row.get(col, "") for col in columns]
self.tree.insert("", "end", values=values)
self.canvas.update_idletasks()
self.canvas.config(scrollregion=self.canvas.bbox("all"))
def show_row_data(self, event):
selected_item = self.tree.selection()
if selected_item:
row_id = self.tree.identify_row(event.y)
if row_id:
index_start = next((i for i, char in enumerate(row_id) if char.isdigit()), None)
if index_start is not None:
row_index_str = row_id[index_start:]
try:
row_index = int(row_index_str) - 1
row_data = (self.data[row_index])
print(row_data)
self.display_row_data(row_data)
except ValueError:
messagebox.showwarning("Invalid Selection", f"Invalid row index: {row_index_str}")
else:
messagebox.showwarning("No Selection", "Please select a row to view.")
def display_row_data(self, row_data):
row_data_window = tk.Toplevel(self.master)
row_data_window.title("Row Data")
row_data_window.configure(bg="white")
row_count = 0
for key, value in row_data.items():
label = tk.Label(row_data_window, text=f"{key}: {value}", bg="black", fg="white", padx=10, pady=5)
label.grid(row=row_count // 4, column=row_count % 4, sticky="w")
row_count += 1
def show_help(self):
help_text = """
Welcome to Queensland Crashes!
Instructions:
1. Load the car crash CSV that you want to read about
2. Use the search button to find specific data
3. Use the scroll down button to scroll down if more rows are available
FOR ADMIN -
1. Press on Admin
2. Input password - (Password1)
3. Edit Data or Create Data
"""
messagebox.showinfo("Help", help_text)
if __name__ == '__main__':
root = CTk()
root.state("zoomed")
root.attributes('-alpha', 1.0)
root.iconbitmap("QLD Icon.ico")
set_appearance_mode("dark")
root.configure(bg="lightgray")
app = RoadSafetyApp(root)
root.mainloop()
I tried many different things but none of them worked, and they all just gave me a blank tkinter screen.