tksheet icon indicating copy to clipboard operation
tksheet copied to clipboard

Issue on Selected rows when Displaying Rows

Open AnonymousVibrate opened this issue 1 year ago • 5 comments

import pandas as pd
from customtkinter import CTk, CTkEntry, CTkButton
from tksheet import Sheet
from tkinter import TOP, BOTH, X

# Sample data
Check = pd.DataFrame([' '])
sample_data = pd.DataFrame([
    ['Apple', 'Banana','Late'], 
    ['REMARK', 'MARKING','Early'],
    ['Apps','Thousand','Very Late']
    ])

data = pd.concat([Check, sample_data], axis=1).fillna('')

# Dictionary to keep track of checkbox states
checkbox_states = {i: False for i in range(len(data))}

def update_checkbox_states(sheet):
    for row_idx in range(sheet.total_rows()):
        if sheet.get_cell_data(row_idx, 0) == True:
            checkbox_states[row_idx] = True
        else:
            checkbox_states[row_idx] = False
    print('DONE UPDATE')

def apply_checkbox_states(sheet):
    for row_idx, state in checkbox_states.items():
        if state:
            sheet.set_cell_data(row_idx, 0, True)
        else:
            sheet.set_cell_data(row_idx, 0, False)
    print('DONE APPLY')
    
def selected_row(event=None):
    global row_edit, rearrange

    row_edit = []
    for box in sheet.get_all_selection_boxes():
        sheet[box].dehighlight()
        data = sheet[box].data
        for row in data:
            row_edit.append(row)

def searching(entry, sheet):
    global rows_to_show, isALL
    key = entry.get().lower()

    if not key:
        sheet.display_rows('all', all_displayed=False)
        isALL = 'all'
    else:
        words = key.split()
        fill = data.values.tolist()
        
        matching_indices = set(range(len(fill)))

        for word in words:
            matching_indices = {idx for idx in matching_indices if any(word in str(cell).lower() for cell in fill[idx])}

        print(matching_indices)
        rows_to_show = list(matching_indices)

        sheet.display_rows(rows_to_show, all_displayed=False, redraw=True, reset_row_positions=True)
        isALL = 'Not-all'

    print('DONE SEARCH')

def custom_sheet():
    global sheet
    tkEntry = CTkEntry(app, fg_color='white', bg_color='white', text_color='black')
    tkEntry.pack(side=TOP, fill=X, expand=True)

    sheet = Sheet(app, data=data.values.tolist())
    sheet.pack(side=TOP, fill=BOTH, expand=True)
    sheet.enable_bindings()
    sheet.checkbox('A', checked=False, redraw=False)

    tkButton = CTkButton(app, text='Search', command=lambda: [update_checkbox_states(sheet), searching(tkEntry, sheet), apply_checkbox_states(sheet)])
    tkButton.pack(side=TOP)

    sheet.extra_bindings(bindings="row_select", func= selected_row)


app = CTk()
app.config(background='white')
custom_sheet()
app.mainloop()

First step: image

Second step: image

Third step: image

Output: [False, 'REMARK', 'MARKING', 'Early']

When I search 'app' in Entry, it hide rows that are not related to search key. When I select the supposedly the 3rd rows. it printed the hidden rows 2.

AnonymousVibrate avatar Jul 19 '24 04:07 AnonymousVibrate

I think I have the same issues. Depending on options I created, I hide rows using sheet_obj.display_rows(rows=rows_to_show, all_displayed = False) where rows_to_show is a list of indexes I want to display, others are not shown. Likewise I hide columns using sheet_obj.display_columns(columns=[0,3,4], all_columns_displayed=False) When I call get_currently_selected, both current_selection.row and current_selection.column are incorrect. Is there a workaround?

agregory999 avatar Jul 30 '24 19:07 agregory999

@AnonymousVibrate Hello, I am struggling to determine an issue when using the following code to test displaying rows:

from tksheet import Sheet
import tkinter as tk
from itertools import islice


class demo(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.data = [
            ["Apple", "Banana", "Late"],
            ["REMARK", "MARKING", "Early"],
            ["Apps", "Thousand", "Very Late"],
        ]
        self.search_bar = tk.Entry(self)
        self.search_bar.pack(side="top", fill="x", expand=True)
        self.search_bar.bind("<Return>", self.search_for)
        self.sheet = Sheet(self, data=self.data)
        self.sheet.pack(side="top", fill="both", expand=True)
        self.sheet.enable_bindings()
        self.sheet.insert_column(idx=0)
        self.sheet.checkbox("A", checked=False, redraw=False)
        self.search_button = tk.Button(self, text="Search", command=self.search_for)
        self.search_button.pack(side="top")

    def search_for(self, event=None):
        key = self.search_bar.get().lower()
        if not key:
            self.sheet.display_rows("all", all_displayed=False, redraw=True, reset_row_positions=True)
        else:
            words = key.split()
            matching_indices = set(
                ind
                for word in words
                for ind, row in enumerate(self.data)
                if any(word in f"{cell}".lower() for cell in islice(row, 1, None))
            )
            if not matching_indices:
                matching_indices = list(range(len(self.data)))
            self.sheet.display_rows(
                matching_indices,
                all_displayed=False,
                redraw=True,
                reset_row_positions=True,
            )


app = demo()
app.mainloop()

Is it possible the issue is related to your example?

ragardner avatar Aug 01 '24 08:08 ragardner

@agregory999 Hello, get_currently_selected returns the displayed index of the row/column, use:

  • https://github.com/ragardner/tksheet/wiki/Version-7#displayed-row-index-to-data
  • https://github.com/ragardner/tksheet/wiki/Version-7#displayed-column-index-to-data

to convert the integers in the currently selected tuple

ragardner avatar Aug 01 '24 08:08 ragardner

@AnonymousVibrate Hello, I am struggling to determine an issue when using the following code to test displaying rows:

from tksheet import Sheet
import tkinter as tk
from itertools import islice


class demo(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.data = [
            ["Apple", "Banana", "Late"],
            ["REMARK", "MARKING", "Early"],
            ["Apps", "Thousand", "Very Late"],
        ]
        self.search_bar = tk.Entry(self)
        self.search_bar.pack(side="top", fill="x", expand=True)
        self.search_bar.bind("<Return>", self.search_for)
        self.sheet = Sheet(self, data=self.data)
        self.sheet.pack(side="top", fill="both", expand=True)
        self.sheet.enable_bindings()
        self.sheet.insert_column(idx=0)
        self.sheet.checkbox("A", checked=False, redraw=False)
        self.search_button = tk.Button(self, text="Search", command=self.search_for)
        self.search_button.pack(side="top")

    def search_for(self, event=None):
        key = self.search_bar.get().lower()
        if not key:
            self.sheet.display_rows("all", all_displayed=False, redraw=True, reset_row_positions=True)
        else:
            words = key.split()
            matching_indices = set(
                ind
                for word in words
                for ind, row in enumerate(self.data)
                if any(word in f"{cell}".lower() for cell in islice(row, 1, None))
            )
            if not matching_indices:
                matching_indices = list(range(len(self.data)))
            self.sheet.display_rows(
                matching_indices,
                all_displayed=False,
                redraw=True,
                reset_row_positions=True,
            )


app = demo()
app.mainloop()

Is it possible the issue is related to your example?

from tksheet import Sheet
import tkinter as tk
from itertools import islice


class demo(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.data = [
            ["Apple", "Banana", "Late"],
            ["REMARK", "MARKING", "Early"],
            ["Apps", "Thousand", "Very Late"],
        ]
        self.search_bar = tk.Entry(self)
        self.search_bar.pack(side="top", fill="x", expand=True)
        self.search_bar.bind("<Return>", self.search_for)
        self.sheet = Sheet(self, data=self.data)
        self.sheet.pack(side="top", fill="both", expand=True)
        self.sheet.enable_bindings()
        self.sheet.insert_column(idx=0)
        self.sheet.checkbox("A", checked=False, redraw=False)
        self.search_button = tk.Button(self, text="Search", command=self.search_for)
        self.search_button.pack(side="top")
        self.sheet.extra_bindings(bindings="row_select", func= self.selected_row)

    def search_for(self, event=None):
        key = self.search_bar.get().lower()
        if not key:
            self.sheet.display_rows("all", all_displayed=False, redraw=True, reset_row_positions=True)
        else:
            words = key.split()
            matching_indices = set(
                ind
                for word in words
                for ind, row in enumerate(self.data)
                if any(word in f"{cell}".lower() for cell in islice(row, 1, None))
            )
            if not matching_indices:
                matching_indices = list(range(len(self.data)))
            self.sheet.display_rows(
                matching_indices,
                all_displayed=False,
                redraw=True,
                reset_row_positions=True,
            )

    def selected_row(self ,event=None):
        global row_edit, rearrange

        row_edit = []
        for box in self.sheet.get_all_selection_boxes():
            self.sheet[box].dehighlight()
            data = self.sheet[box].data
            for row in data:
                row_edit.append(row)

        print(row_edit)


app = demo()
app.mainloop()

Please try this updated code. It will print [False, 'REMARK', 'MARKING', 'Early'] after you select the 3rd row.

AnonymousVibrate avatar Aug 01 '24 08:08 AnonymousVibrate

Thank you for the update,

My apologies, there is not enough documentation on this,

I think the above issue will be fixed if you change the displayed row of the box to a data row integer,

def selected_row(self ,event=None):
        global row_edit, rearrange

        row_edit = []
        for box in self.sheet.get_all_selection_boxes():
            row_number = self.sheet.datarn(box.from_r)
            row = self.sheet[row_number].data
            for cell in row:
                row_edit.append(cell)

        print(row_edit)

I will add more documentation on the topic but basically:

  • Displayed cell coordinates ignore hidden rows/columns when indexing cells.
  • Data cell coordinates include hidden rows/columns in indexing cells.

ragardner avatar Aug 01 '24 12:08 ragardner