ragardner / tksheet

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

Sheet object takes focus when setting sheet data? How to inhibit? #233

Closed hans-fritz-pommes closed 3 months ago

hans-fritz-pommes commented 3 months ago

Hello ragardner, It seems like a Sheet object takes the focus when it was redrawed. I noticed this the following way: I have a window opened to edit a row and when I save the row, the function save_row starts another function update_sheet in a threading.Thread to load the new data from an array (which takes about 1 second) and redraw the sheet with the changed data.

Right after the command Thread(target=update_sheet).start(), save_row focuses an Entry and returns.

When I use this, I notice, that the Entry gets the focus, but after about one second, the focus is taken away and I have to refocus manually.

Could it be, that a Sheet object takes the focus after redrawing? And if yes, how to inhibit this?

Thank you for your time, HansFritzPommes

ragardner commented 3 months ago

Hello,

It is difficult to know what to change without an example sorry, there are numerous calls to self.focus_set() in the main_table.py file, none of them are after a redraw though and some of them are important.

For example after closing a text editor focus is returned to the table so a keypress such as tab can change the selected cell

hans-fritz-pommes commented 3 months ago

Thank you for the reply;

I will look for the problematic self.focus_set() call or/and send you an example soon.

HansFritzPommes

hans-fritz-pommes commented 3 months ago

Hello again, I found out the path to a self.focus_set(): It's not (how I was thinking) called after a redraw, but after hiding the text_editor with the reason "Escape".

The trace is (very long): file sheet.py function set_sheet_data(self) command return self.MT.data_reference(...) -> file main_table.py ("MT") function data_reference(self) command self.hide_dropdown_editor_all_canvases() -> function hide_dropdown_editor_all_canvases(self) command self.*.hide_text_editor_and_dropdown(redraw=...) -> function hide_text_editor_and_dropdown(self,redraw=...) command self.hide_text_editor("Escape") -> function hide_text_editor(self,reason=...) commands if reason=="Escape": self.focus_set()

It would be great if you could add a parameter like inhibit_focus_after : bool = False in the function Sheet().set_sheet_data which is given through the whole trace...

Thank you in advance

HansFritzPommes

hans-fritz-pommes commented 3 months ago

Here is an example:

import tkinter as tk
import tksheet
from time import sleep
from threading import Thread
top = tk.Tk()
sheet = tksheet.Sheet(top)
sheet_data=[[f"{ri+cj}" for cj in range(4)] for ri in range(4)]
sheet.pack()
sheet.enable_bindings()
sheet.set_sheet_data(sheet_data)
def update_and_wait():
    t.focus()
    sleep(1) # to simulate very big arrays which need more time to get loaded
    update_sheet()
def open_window():
    global t
    test=tk.Toplevel(top)
    test.transient(top)
    t=tk.Button(test,text="test",command=lambda:start(update_and_wait))
    t.pack()
    t.focus()
def update_sheet():
    sheet.set_sheet_data(sheet_data)
    print("data was loaded")
def start(function,args:list=[]):
    thread=Thread(target=function,args=args)
    thread.start()
b=tk.Button(top,text="open window",command=open_window)
b.place(x=4,y=4)
top.mainloop()
ragardner commented 3 months ago

Hello,

Thank you very much for taking the time to identify the issue and for the example,

I agree with you this was an issue, what I have done in version 7.2.10 is removed the focus_set() line from hide_text_editor() and replaced the missing focus_set() calls only where they were needed

Effectively the sheet was stealing focus whenever its data was set! not good and thank you again for reporting the issue and tracking it down so well

Let me know if you have any further issues

hans-fritz-pommes commented 3 months ago

Thank you very much! Now it works fine.