tksheet icon indicating copy to clipboard operation
tksheet copied to clipboard

[Question] Edition popup window

Open skedus opened this issue 3 years ago • 2 comments

Hi Ragarder, I would like to have your point of view if it is possible. I want to create a popup windows to edit a cell, for that I'm using extra binding : begin_edit_cell and en_edit_cell

In my application the popup windows is more complex but in the code example below, I simplified to a simple entry to reproduce the problem I have. 1 - when you double clic on one cell of the column2 a popup window appear (good) you can change the value 2 - but then I do not find the correct sequence to refresh the sheet with the new value (if you press Escape the new value appears)

I tested many internal function of tksheet to escape the text_editor cell

Do you see a better way to do it ? it seems to be a problem of focus on the cell, but I do not find how to avoid it. You can see some of my tests in comment in the ok_cb() callback (the set_cell_data and set_all_cell_sizes_to_text seems to work properly)

Thank you for your help

#!/usr/bin/env python3

import tkinter as tk
from tksheet import Sheet

root = tk.Tk()
frame = tk.Frame(root)

def end_edit_cell(event):
    """
    binding function
    row = event[0] / col = event[1]
    """
    row = event[0] 
    col = event[1]
    print("++> end edit: " + str(row) + "," + str(col) + " -> " + sheet.get_cell_data(row, col))
    

def begin_edit_cell(event):
    """
    binding function
    row = event[0] / col = event[1]
    """
    print("++> begin edit")
    row = event[0] 
    col = event[1]
    col_name = sheet.headers()[col]

    # Popup window only on col2
    if col_name == 'col2':
        win = tk.Toplevel(root)
        x = root.winfo_rootx() + 20
        y = root.winfo_rooty() + 20
        win.geometry("+{}+{}".format(x, y))
        win.transient(root)
        win.grab_set()
        win.deiconify()

        f = tk.Frame(win, width=200, height=200)
        f.pack(fill=tk.BOTH, expand=tk.YES, padx=10, pady=10)

        value = tk.StringVar()
        e = tk.Entry(f, textvariable=value)
        e.pack()

        value.set(data[row][col])

        fbutton = tk.Frame(f, padx=10, pady=10)
        fbutton.pack(fill=tk.X, expand=tk.YES)

        b0 = tk.Button(
            fbutton,
            text="Ok",
            width=15,
            command=lambda win=win, row=row, col=col, value=value: ok_cb(win, row, col, value),
        )
        b0.pack(side=tk.RIGHT)

        b1 = tk.Button(
            fbutton,
            text="Cancel",
            width=15,
            command=lambda win=win: cancel_cb(win),
        )
        b1.pack(side=tk.RIGHT)

        f.wait_window(win)

         
def ok_cb(win, row, col, value):
    print("++> OK try to set value: " + str(row) + "," + str(col) + " " + str(value.get()))
    #sheet.set_text_editor_value(text=str(value.get()), r=row, c=col)
    sheet.set_cell_data(row, col, value=value.get())
    sheet.set_all_cell_sizes_to_text()
    win.destroy()
    #sheet.deselect("all")
    #sheet.event_generate("<Escape>", when="now")
    sheet.MT.destroy_text_editor("Escape")
    #sheet.destroy_text_editor()
    #a = sheet.MT.get_text_editor_value((row, col, "Escape"))
    #print("++> OK : " + str(a))

def cancel_cb(win):
    print("++> CANCEL")
    win.destroy()

# ----------------------------------------------------------------------------
# Main program
# ----------------------------------------------------------------------------
if __name__ == "__main__":

    data = [
        ["aaaa", "aaaa", "aa"],
        ["bbbbb", "bb", "b"],
        ["ccc", "ccc", "ccc"],
        ["dddddd", "ddd", "dddddddd"],
        ["xxx", "xxx", "xxx"]
    ]
    sheet = Sheet(frame, 
        data=data,
        headers=["col1", "col2", "col3"],
    )
    sheet.pack(expand=tk.YES, fill=tk.BOTH)

    sheet.enable_bindings(
        (
            "single_select",  # "single_select" or "toggle_select"
            "arrowkeys",
            "edit_cell",
        )
    )
    sheet.extra_bindings("begin_edit_cell", begin_edit_cell)
    sheet.extra_bindings("end_edit_cell", end_edit_cell)
    sheet.set_all_cell_sizes_to_text() # cell resizing moved here
    frame.pack(fill=tk.BOTH, expand=tk.YES)

    root.mainloop()

skedus avatar Jan 11 '22 14:01 skedus

Sorry for the noise, I asked you few month ago to add a try/catch on extra_binding functions and you did it (I forgot that) this is solving this issue.

by adding a raise in the begin_edit_cell function when the popup windows is closed all is done properly here below the correction

#!/usr/bin/env python3

import tkinter as tk
from tksheet import Sheet

root = tk.Tk()
frame = tk.Frame(root)

def end_edit_cell(event):
    """
    binding function
    row = event[0] / col = event[1]
    """
    row = event[0] 
    col = event[1]
    print("++> end edit: " + str(row) + "," + str(col) + " -> " + sheet.get_cell_data(row, col))
    

def begin_edit_cell(event):
    """
    binding function
    row = event[0] / col = event[1]
    """
    print("++> begin edit")
    row = event[0] 
    col = event[1]
    col_name = sheet.headers()[col]

    # Popup window only on col2
    if col_name == 'col2':
        win = tk.Toplevel(root)
        x = root.winfo_rootx() + 20
        y = root.winfo_rooty() + 20
        win.geometry("+{}+{}".format(x, y))
        win.transient(root)
        win.grab_set()
        win.deiconify()

        f = tk.Frame(win, width=200, height=200)
        f.pack(fill=tk.BOTH, expand=tk.YES, padx=10, pady=10)

        value = tk.StringVar()
        e = tk.Entry(f, textvariable=value)
        e.pack()
        value.set(data[row][col])
        fbutton = tk.Frame(f, padx=10, pady=10)
        fbutton.pack(fill=tk.X, expand=tk.YES)

        b0 = tk.Button(fbutton,text="Ok", width=15,command=lambda win=win, row=row, col=col, value=value: ok_cb(win, row, col, value),)
        b0.pack(side=tk.RIGHT)

        b1 = tk.Button(fbutton,text="Cancel", width=15, command=lambda win=win: cancel_cb(win),)
        b1.pack(side=tk.RIGHT)

        f.wait_window(win)
        # using raise to stop edition at begin_edit_cell level all is done in ok_cb function already
        raise
         
def ok_cb(win, row, col, value):
    print("++> OK try to set value: " + str(row) + "," + str(col) + " " + str(value.get()))
    sheet.set_cell_data(row, col, value=value.get())
    sheet.set_all_cell_sizes_to_text() 
    win.destroy()

def cancel_cb(win):
    print("++> CANCEL")
    win.destroy()

# ----------------------------------------------------------------------------
# Main program
# ----------------------------------------------------------------------------
if __name__ == "__main__":

    data = [
        ["aaaa", "aaaa", "aa"],
        ["bbbbb", "bb", "b"],
        ["ccc", "ccc", "ccc"],
        ["dddddd", "ddd", "dddddddd"],
        ["xxx", "xxx", "xxx"]
    ]
    sheet = Sheet(frame, 
        data=data,
        headers=["col1", "col2", "col3"],
    )
    sheet.pack(expand=tk.YES, fill=tk.BOTH)

    sheet.enable_bindings(
        (
            "single_select",  # "single_select" or "toggle_select"
            "arrowkeys",
            "edit_cell",
        )
    )
    sheet.extra_bindings("begin_edit_cell", begin_edit_cell)
    sheet.extra_bindings("end_edit_cell", end_edit_cell)
    sheet.set_all_cell_sizes_to_text() # cell resizing moved here
    frame.pack(fill=tk.BOTH, expand=tk.YES)

    root.mainloop()

skedus avatar Jan 11 '22 15:01 skedus

@skedus, thank you for asking this question, and especially for updating it with how you fixed it! I had a very similar problem and was going crazy trying to figure out how to resolve it. Adding "break" was just the solution I was looking for.

KirklandBordeaux avatar Jan 17 '22 22:01 KirklandBordeaux