ragardner / tksheet

Python tkinter table widget for displaying tabular data
https://pypi.org/project/tksheet/
MIT License
408 stars 50 forks source link

undo and validate_edit callback #256

Open skedus opened 15 hours ago

skedus commented 15 hours ago

Hi, For each cell edition I need to process an external action, the validate_edit callback is working fine for it for most edition (perfect :-) ). Now I try to manage the "undo" it seems that the validate_edit is not use. I tried the documented command:

self.sheet.edit_validation(self.validate_edits).bind("<<SheetModified>>", self.sheet_modified)

during undo the self.sheet_modified is well call but I have no indication of the cells modified with the new values (only old values)

I tried as well extra_binding end_undo but this is the same event as self.sheet_modified

Is there a way to manage each cell undo such validate_edit, with the cell row,col and new value of the cell ? Thank you

Here below the simple code I use to display event. 1 - I modify a cell 2 - Ctr-z to make the undo

from tksheet import Sheet
import tkinter as tk
import pprint

class demo(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)
        self.frame = tk.Frame(self)
        self.frame.grid_columnconfigure(0, weight=1)
        self.frame.grid_rowconfigure(0, weight=1)

        self.sheet = Sheet(
            self.frame,
            data=[[f"Row {r}, Column {c}" for c in range(6)] for r in range(21)],
            column_width=180,
            height=700,
            width=1100,
        )
        self.sheet.enable_bindings(
            "edit_cell",
            "copy",
            "paste",
            "cut",
            "undo",
            "delete",
            "rc_insert_row",
            "rc_delete_row",
            "rc_select",
            "arrowkeys",
            "column_width_resize",
            "row_select",
            "single_select",
        )

        for row in range(self.sheet.get_total_rows()):
            self.sheet.create_checkbox(
                r=row,
                c=1,
                checked=False,
                check_function=lambda event=None: self.click_checkbox(event),
            )

        self.frame.grid(row=0, column=0, sticky="nswe")
        self.sheet.grid(row=0, column=0, sticky="nswe")

        self.sheet.edit_validation(self.validate_edits).bind("<<SheetModified>>", self.sheet_modified)
        self.sheet.extra_bindings("end_undo", self.end_undo)

    def click_checkbox(self, event):
        """Custom checkbox"""
        print(f"[click_checkbox] eventname={event.eventname} row={event.row} col={event.column} value={event.value}")

    def end_undo(self, event):
        print(f"[end_undo] event=")
        pprint.pp(event)

    def validate_edits(self, event):
        print(f"[validate_edits] event=")
        pprint.pp(event)
        return event.value

    def sheet_modified(self, event):
        print(f"[sheet_modified] event=")
        pprint.pp(event)

app = demo()
app.mainloop()
ragardner commented 5 hours ago

Hello,

Thanks for your thoughts and your example,

I have decided to add edit validation checks to undo / redo for cell edits. The logic is basically that undo and redo are user actions, in the same way that cut, delete and paste are and perhaps there has been changes to the validation since the action or something

The work should be completed this week sometime

About the old values being in the event data -

If its not an edit validation bound event, but a post action event such as with the extra_bindings you've got in your example you should be able to use the coordinates of the cell edits in the event data to get the new values from the sheet

Kind regards