Editing data for a certain row CSV file Python

30 Views Asked by At

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.

0

There are 0 best solutions below