-
Notifications
You must be signed in to change notification settings - Fork 58
Version 6
- About tksheet
- Installation and Requirements
- Basic Initialization
- Initialization Options
- Header and Index
- Setting Table Data
- Getting Table Data
- Bindings and Functionality
- Identifying Bound Event Mouse Position
- Table Colors
- Highlighting Cells
- Text Font and Alignment
- Row Heights and Column Widths
- Getting Selected Cells
- Modifying Selected Cells
- Modifying and Getting Scroll Positions
- Readonly Cells
- Hiding Columns
- Hiding Rows
- Hiding Table Elements
- Cell Text Editor
- Dropdown Boxes
- Check Boxes
- Cell Formatting
- Table Options and Other Functions
- Example Loading Data from Excel
- Example Custom Right Click and Text Editor Validation
- Example Displaying Selections
- Example List Box
- Example Header Dropdown Boxes and Row Filtering
- Example ReadMe Screenshot Code
- Example Saving tksheet as a csv File
- Example Using and Creating Formatters
- Contributing
tksheet is a Python tkinter table widget written in pure python. It is licensed under the MIT license.
It works using tkinter canvases and moves lines, text and rectangles around for only the visible portion of the table.
Cell values can be any class with a str method.
Some examples of things that are not possible with tksheet:
- Cell merging
- Cell text wrap
- Changing font for individual cells
- Different fonts for index and table
- Mouse drag copy cells
- Cell highlight borders
- Highlighting continuous multiple cells with a single border
tksheet is available through PyPi (Python package index) and can be installed by using Pip through the command line pip install tksheet
Alternatively you can download the source code and (inside the tksheet directory) use the command line python setup.py develop
tksheet requires a Python version of 3.7 or higher.
Like other tkinter widgets you need only the Sheet()s parent as an argument to initialize a Sheet() e.g.
sheet = Sheet(my_frame_widget)-
my_frame_widgetwould be replaced by whatever widget is yourSheet()s parent.
As an example, this is a tkinter program involving a Sheet() widget
from tksheet import Sheet
import tkinter as tk
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}\nnewline1\nnewline2" for c in range(50)] for r in range(500)])
self.sheet.enable_bindings()
self.frame.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.grid(row = 0, column = 0, sticky = "nswe")
app = demo()
app.mainloop()This is a full list of all the start up arguments, the only required argument is the sheets parent, everything else has default arguments.
(
parent,
name: str = "!sheet",
show_table: bool = True,
show_top_left: bool = True,
show_row_index: bool = True,
show_header: bool = True,
show_x_scrollbar: bool = True,
show_y_scrollbar: bool = True,
width: int = None,
height: int = None,
headers: list = None,
header: list = None,
default_header: str = "letters", #letters, numbers or both
default_row_index: str = "numbers", #letters, numbers or both
to_clipboard_delimiter = "\t",
to_clipboard_quotechar = '"',
to_clipboard_lineterminator = "\n",
from_clipboard_delimiters = ["\t"],
show_default_header_for_empty: bool = True,
show_default_index_for_empty: bool = True,
page_up_down_select_row: bool = True,
expand_sheet_if_paste_too_big: bool = False,
paste_insert_column_limit: int = None,
paste_insert_row_limit: int = None,
show_dropdown_borders: bool = False,
arrow_key_down_right_scroll_page: bool = False,
enable_edit_cell_auto_resize: bool = True,
edit_cell_validation: bool = True,
data_reference: list = None,
data: list = None,
startup_select: tuple = None, #either (start row, end row, "rows"), (start column, end column, "rows") or (cells start row, cells start column, cells end row, cells end column, "cells")
startup_focus: bool = True,
total_columns: int = None,
total_rows: int = None,
column_width: int = 120,
header_height: str = "1", #str or int
max_colwidth: str = "inf", #str or int
max_rh: str = "inf", #str or int
max_header_height: str = "inf", #str or int
max_row_width: str = "inf", #str or int
row_index: list = None,
index: list = None,
after_redraw_time_ms: int = 100,
row_index_width: int = 100,
auto_resize_default_row_index: bool = True,
auto_resize_columns: Union[int, None] = None,
auto_resize_rows: Union[int, None] = None,
set_all_heights_and_widths: bool = False,
set_cell_sizes_on_zoom: bool = False,
row_height: str = "1", #str or int
zoom: int = 100,
font: tuple = get_font(),
header_font: tuple = get_heading_font(),
index_font: tuple = get_index_font(), #currently has no effect
popup_menu_font: tuple = get_font(),
align: str = "w",
header_align: str = "center",
row_index_align: str = "center",
displayed_columns: list = [],
all_columns_displayed: bool = True,
max_undos: int = 30,
outline_thickness: int = 0,
outline_color: str = theme_light_blue['outline_color'],
column_drag_and_drop_perform: bool = True,
row_drag_and_drop_perform: bool = True,
empty_horizontal: int = 150,
empty_vertical: int = 100,
selected_rows_to_end_of_window: bool = False,
horizontal_grid_to_end_of_window: bool = False,
vertical_grid_to_end_of_window: bool = False,
show_vertical_grid: bool = True,
show_horizontal_grid: bool = True,
display_selected_fg_over_highlights: bool = False,
show_selected_cells_border: bool = True,
theme = "light blue",
popup_menu_fg = theme_light_blue['popup_menu_fg'],
popup_menu_bg = theme_light_blue['popup_menu_bg'],
popup_menu_highlight_bg = theme_light_blue['popup_menu_highlight_bg'],
popup_menu_highlight_fg = theme_light_blue['popup_menu_highlight_fg'],
frame_bg = theme_light_blue['table_bg'],
table_grid_fg = theme_light_blue['table_grid_fg'],
table_bg = theme_light_blue['table_bg'],
table_fg = theme_light_blue['table_fg'],
table_selected_cells_border_fg = theme_light_blue['table_selected_cells_border_fg'],
table_selected_cells_bg = theme_light_blue['table_selected_cells_bg'],
table_selected_cells_fg = theme_light_blue['table_selected_cells_fg'],
table_selected_rows_border_fg = theme_light_blue['table_selected_rows_border_fg'],
table_selected_rows_bg = theme_light_blue['table_selected_rows_bg'],
table_selected_rows_fg = theme_light_blue['table_selected_rows_fg'],
table_selected_columns_border_fg = theme_light_blue['table_selected_columns_border_fg'],
table_selected_columns_bg = theme_light_blue['table_selected_columns_bg'],
table_selected_columns_fg = theme_light_blue['table_selected_columns_fg'],
resizing_line_fg = theme_light_blue['resizing_line_fg'],
drag_and_drop_bg = theme_light_blue['drag_and_drop_bg'],
index_bg = theme_light_blue['index_bg'],
index_border_fg = theme_light_blue['index_border_fg'],
index_grid_fg = theme_light_blue['index_grid_fg'],
index_fg = theme_light_blue['index_fg'],
index_selected_cells_bg = theme_light_blue['index_selected_cells_bg'],
index_selected_cells_fg = theme_light_blue['index_selected_cells_fg'],
index_selected_rows_bg = theme_light_blue['index_selected_rows_bg'],
index_selected_rows_fg = theme_light_blue['index_selected_rows_fg'],
index_hidden_rows_expander_bg = theme_light_blue['index_hidden_rows_expander_bg'],
header_bg = theme_light_blue['header_bg'],
header_border_fg = theme_light_blue['header_border_fg'],
header_grid_fg = theme_light_blue['header_grid_fg'],
header_fg = theme_light_blue['header_fg'],
header_selected_cells_bg = theme_light_blue['header_selected_cells_bg'],
header_selected_cells_fg = theme_light_blue['header_selected_cells_fg'],
header_selected_columns_bg = theme_light_blue['header_selected_columns_bg'],
header_selected_columns_fg = theme_light_blue['header_selected_columns_fg'],
header_hidden_columns_expander_bg = theme_light_blue['header_hidden_columns_expander_bg'],
top_left_bg = theme_light_blue['top_left_bg'],
top_left_fg = theme_light_blue['top_left_fg'],
top_left_fg_highlight = theme_light_blue['top_left_fg_highlight'])-
auto_resize_columns(int,None) if set as anintthe columns will automatically resize to fit the width of the window, theintvalue being the minimum of each column in pixels. -
auto_resize_rows(int,None) if set as anintthe rows will automatically resize to fit the height of the window, theintvalue being the minimum height of each row in pixels. -
startup_selectselects cells, rows or columns at initialization by using atuplee.g.(0, 0, "cells")for cell A0 or(0, 5, "rows")for rows 0 to 5. -
data_referenceanddataare essentially the same. -
row_indexandindexare the same,indextakes priority, same as withheadersandheader. -
edit_cell_validation(bool) is used whenextra_bindings()have been set for cell edits. If a bound function returns something other thanNoneit will be used as the cell value instead of the user input.-
Truemakes data edits take place after the binding function is run. -
Falsemakes data edits take place before the binding function is run.
-
You can change these settings after initialization using the set_options() function.
headers(newheaders = None, index = None, reset_col_positions = False, show_headers_if_not_sheet = True, redraw = False)- Using an integer
intfor argumentnewheadersmakes the sheet use that row as a header e.g.headers(0)means the first row will be used as a header (the first row will not be hidden in the sheet though), this is sort of equivalent to freezing the row. - Leaving
newheadersasNoneand using theindexargument returns the existing header value in that index. - Leaving all arguments as default e.g.
headers()returns existing headers.
row_index(newindex = None, index = None, reset_row_positions = False, show_index_if_not_sheet = True, redraw = False)- Using an integer
intfor argumentnewindexmakes the sheet use that column as an index e.g.row_index(0)means the first column will be used as an index (the first column will not be hidden in the sheet though), this is sort of equivalent to freezing the column. - Leaving
newindexasNoneand using theindexargument returns the existing row index value in that index. - Leaving all arguments as default e.g.
row_index()returns the existing row index.
set_sheet_data(data = [[]],
reset_col_positions = True,
reset_row_positions = True,
redraw = True,
verify = False,
reset_highlights = False)-
data(list) has to be a list of lists for full functionality, for display only a list of tuples or a tuple of tuples will work. -
reset_col_positionsandreset_row_positions(bool) whenTruewill reset column widths and row heights. -
redraw(bool) refreshes the table after setting new data. -
verify(bool) goes throughdataand checks if it is a list of lists, will raise error if not, disabled by default. -
reset_highlights(bool) resets all table cell highlights.
set_cell_data(r, c, value = "", redraw = False)insert_row(values: Union[list, int, None] = None,
idx: Union[str, int] = "end",
height = None,
deselect_all = False,
add_columns = False,
mod_row_positions = True,
redraw = True)- Leaving
valuesasNoneinserts an empty row, e.g.insert_row()will append an empty row to the sheet. -
heightis the new rows displayed height in pixels, leave asNonefor default. -
add_columnschecks the rest of the sheets rows are at least the length as the new row, leave asFalsefor better performance.
set_column_data(c, values = tuple(), add_rows = True, redraw = False)-
add_rowsadds extra rows to the sheet if the column data doesn't fit within current sheet dimensions.
insert_column(values = None, idx = "end", width = None, deselect_all = False, add_rows = True, equalize_data_row_lengths = True,
mod_column_positions = True,
redraw = False)insert_columns(columns = 1, idx = "end", widths = None, deselect_all = False, add_rows = True, equalize_data_row_lengths = True,
mod_column_positions = True,
redraw = False)-
columnscan be eitherintor iterable of iterables.
set_row_data(r, values = tuple(), add_columns = True, redraw = False)insert_rows(rows: Union[list, int] = 1,
idx: Union[str, int] = "end",
heights = None,
deselect_all = False,
add_columns = True,
mod_row_positions = True,
redraw = True)-
rowscan be eitherintor iterable of iterables.
sheet_data_dimensions(total_rows = None, total_columns = None)delete_row(idx = 0, deselect_all = False, redraw = True)delete_rows(rows: set = set(), deselect_all = False, redraw = True)- Does not maintain selections.
total_rows(number = None, mod_positions = True, mod_data = True)total_columns(number = None, mod_positions = True, mod_data = True)set_sheet_data_and_display_dimensions(total_rows = None, total_columns = None)move_row(row, moveto)move_rows(moveto: int, to_move_min: int, number_of_rows: int, move_data: bool = True, index_type = "displayed", create_selections: bool = True, redraw = False)-
to_move_minis the first row in the series of rows. -
index_type(str) either"displayed"or"data"
delete_column(idx = 0, deselect_all = False, redraw = True)delete_columns(columns: set = set(), deselect_all = False, redraw = True)- Does not maintain selections.
move_column(column, moveto)move_columns(moveto: int, to_move_min: int, number_of_columns: int, move_data: bool = True, index_type = "displayed", create_selections: bool = True, redraw = False)-
to_move_minis the first column in the series of columns. -
index_type(str) either"displayed"or"data", e.g. if columns are hidden and you want to supply the function with data indexes not sheet displayed indexes.
equalize_data_row_lengths()- Makes every list in the table have the same number of elements, goes by longest list. This will only affect the data variable, not visible columns.
Modify widget height and width in pixels
height_and_width(height = None, width = None)-
height(int) set a height in pixels -
width(int) set a width in pixels If both arguments areNonethen table will reset to default tkinter canvas dimensions.
This is useful if your sheet is very large and you don't want to create an extra list in memory (it does actually generate one row at a time and not from a pre-built list).
yield_sheet_rows(get_displayed = False,
get_header = False,
get_index = False,
get_index_displayed = True,
get_header_displayed = True,
only_rows = None,
only_columns = None)get_sheet_data(get_displayed = False,
get_header = False,
get_index = False,
get_index_displayed = True,
get_header_displayed = True,
only_rows = None,
only_columns = None)Note:
- The following keyword arguments both behave the same way for
yield_sheet_rows()andget_sheet_data().
Arguments:
-
get_displayed(bool) ifTrueit will return cell values as they are displayed on the screen. IfFalseit will return any underlying data, for example if the cell is formatted. -
get_header(bool) ifTrueit will return the header of the sheet even if there is not one. -
get_index(bool) ifTrueit will return the index of the sheet even if there is not one. -
get_index_displayed(bool) ifTrueit will return whatever index values are displayed on the screen, for example if there is a dropdown box withtextset. -
get_header_displayed(bool) ifTrueit will return whatever header values are displayed on the screen, for example if there is a dropdown box withtextset. -
only_rows(None,iterable) with this argument you can supply an iterable of row indexes in any order to be the only rows that are returned. -
only_columns(None,iterable) with this argument you can supply an iterable of column indexes in any order to be the only columns that are returned.
@property
data()- e.g.
self.sheet.data
.MT.data- You can use this to directly modify or retrieve the main table's data e.g.
cell_0_0 = my_sheet_name_here.MT.data[0][0]. Note that this is the raw data and if there are cell formatters it will include the cell's formatter class, as such it is not recommended to use this to retrieve or modify data unless you know what you are doing.
get_cell_data(r, c, get_displayed = False)get_row_data(r,
get_displayed = False,
get_index = False,
get_index_displayed = True,
only_columns = None)- The above arguments behave the same way as for
get_sheet_data().
get_column_data(c,
get_displayed = False,
get_header = False,
get_header_displayed = True,
only_rows = None)- The above arguments behave the same way as for
get_sheet_data().
Get an empty value for a specific cell.
get_value_for_empty_cell(
r,
c,
r_ops=True,
c_ops=True,
)Sheet objects also have some functions similar to lists. Note that these functions do not include the header or index.
Iterate over table rows:
for row in my_sheet:
print (row)
# and in reverse
for row in reversed(my_sheet):
print (row)Check if the table has a particular value (membership):
# returns True or False
search_value = "the cell value I'm looking for"
print (search_value in my_sheet)- Can also check if a row is in the sheet.
get_total_rows(include_index = False)get_total_columns(include_header = False)enable_bindings(*bindings)-
bindings(str) options are (rc stands for right click):- "all"
- "single_select"
- "toggle_select"
- "drag_select"
- "select_all"
- "column_drag_and_drop" / "move_columns"
- "row_drag_and_drop" / "move_rows"
- "column_select"
- "row_select"
- "column_width_resize"
- "double_click_column_resize"
- "row_width_resize"
- "column_height_resize"
- "arrowkeys" # all arrowkeys including page up and down
- "up"
- "down"
- "left"
- "right"
- "prior" # page up
- "next" # page down
- "row_height_resize"
- "double_click_row_resize"
- "right_click_popup_menu"
- "rc_select"
- "rc_insert_column"
- "rc_delete_column"
- "rc_insert_row"
- "rc_delete_row"
- "ctrl_click_select"
- "ctrl_select"
- "copy"
- "cut"
- "paste"
- "delete"
- "undo"
- "edit_cell"
- "edit_header"
- "edit_index"
Notes:
-
"edit_header","edit_index","ctrl_select"and"ctrl_click_select"are not enabled bybindings = "all"and have to be enabled individually, double click or right click (if enabled) on header/index cells to edit. -
"ctrl_select"and"ctrl_click_select"are the same and you can use either one. - To allow table expansion when pasting data which doesn't fit in the table use either:
-
expand_sheet_if_paste_too_big = Truein sheet initialization arguments or sheet.set_options(expand_sheet_if_paste_too_big = True)
-
Example:
-
sheet.enable_bindings("all", "edit_header", "edit_index", "ctrl_select")to enable absolutely everything.
disable_bindings(*bindings)extra_bindings(bindings, func = None)Notes:
- There are several ways to use this function:
-
bindingsas astrandfuncas eitherNoneor a function. UsingNonewithfuncwill effectively unbind the function.extra_bindings("edit_cell", func=my_function)
-
bindingsas aniterableofstrs andfuncas eitherNoneor a function. UsingNonewithfuncwill effectively unbind the function.extra_bindings(["all_select_events", "copy", "cut"], func=my_function)
-
bindingsas aniterableoflists ortuples with length of two, e.g.-
extra_bindings([(binding, function), (binding, function), ...])In this example you could also useNonein the place offunctionto unbind the binding. - In this case the arg
funcis totally ignored.
-
-
- Upon an event being triggered the bound function will be sent a namedtuple containing variables relevant to that event, use
print()or similar to see all the variable names in the event. Each event contains different variable names with the exception ofeventnamee.g.event.eventname - For most of the
"end_..."events the bound function is run before the value is set. - The bound function for
"end_edit_cell"is run before the cell data is set in order that a return value can set the cell instead of the user input. Using the event you can assess the user input and if needed override it with a return value which is notNone. IfNoneis the return value then the user input will NOT be overridden. The settingedit_cell_validation(see initialization or the functionset_options()) can be used to turn off this return value checking. Theedit_cellbindings also run if header/index editing is turned on.
Arguments:
-
bindings(str) options are:"begin_copy", "begin_ctrl_c""ctrl_c", "end_copy", "end_ctrl_c", "copy""begin_cut", "begin_ctrl_x""ctrl_x", "end_cut", "end_ctrl_x", "cut""begin_paste", "begin_ctrl_v""ctrl_v", "end_paste", "end_ctrl_v", "paste""begin_undo", "begin_ctrl_z""ctrl_z", "end_undo", "end_ctrl_z", "undo""begin_delete_key", "begin_delete""delete_key", "end_delete", "end_delete_key", "delete""begin_edit_cell", "begin_edit_table""end_edit_cell", "edit_cell", "edit_table""begin_edit_header""end_edit_header", "edit_header""begin_edit_index""end_edit_index", "edit_index""begin_row_index_drag_drop", "begin_move_rows""row_index_drag_drop", "move_rows", "end_move_rows", "end_row_index_drag_drop""begin_column_header_drag_drop", "begin_move_columns""column_header_drag_drop", "move_columns", "end_move_columns", "end_column_header_drag_drop""begin_rc_delete_row", "begin_delete_rows""rc_delete_row", "end_rc_delete_row", "end_delete_rows", "delete_rows""begin_rc_delete_column", "begin_delete_columns""rc_delete_column", "end_rc_delete_column","end_delete_columns", "delete_columns""begin_rc_insert_column", "begin_insert_column", "begin_insert_columns", "begin_add_column","begin_rc_add_column", "begin_add_columns""rc_insert_column", "end_rc_insert_column", "end_insert_column", "end_insert_columns", "rc_add_column", "end_rc_add_column", "end_add_column", "end_add_columns""begin_rc_insert_row", "begin_insert_row", "begin_insert_rows", "begin_rc_add_row", "begin_add_row", "begin_add_rows""rc_insert_row", "end_rc_insert_row", "end_insert_row", "end_insert_rows", "rc_add_row", "end_rc_add_row", "end_add_row", "end_add_rows""row_height_resize""column_width_resize""cell_select""select_all""row_select""column_select""drag_select_cells""drag_select_rows""drag_select_columns""shift_cell_select""shift_row_select""shift_column_select""deselect""all_select_events", "select", "selectevents", "select_events""all_modified_events", "sheetmodified", "sheet_modified" "modified_events", "modified""bind_all""unbind_all"
-
funcargument is the function you want to send the binding event to. - Using one of the following
"all_modified_events", "sheetmodified", "sheet_modified" "modified_events", "modified"will make any insert, delete or cell edit including pastes and undos send an event to your function. Please note that this will mean your function will have to return a value to use for cell edits unless the settingedit_cell_validationisFalse.
popup_menu_add_command(label, func, table_menu = True, index_menu = True, header_menu = True)popup_menu_del_command(label = None)- If
labelisNonethen it removes all.
disable_bindings(bindings = "all")basic_bindings(enable = False)- Also enables/disables zoom in/out.
edit_bindings(enable = False)cell_edit_binding(enable = False, keys = [])-
keyscan be used to bind more keys to open a cell edit window
bind(binding, func, add = None)-
addwill only work for bindings which are not the following:"<ButtonPress-1>","<ButtonMotion-1>","<ButtonRelease-1>","<Double-Button-1>","<Motion>"and lastly whichever is your operating systems right mouse click button -
bindingas well as being able to receive the usual tkinterbind()arguments such as key presses can also receive<<SheetModified>>and<<SheetRedrawn>>which are emitted every time there is such an event. Their bound functions must be have at least one parameter and the event object has the following layout:
{
"sheetname": "!sheet",
}unbind(binding)cut(event = None)
copy(event = None)
paste(event = None)
delete(event = None)
undo(event = None)The below functions require a mouse click event, for example you could bind right click, example here, and then identify where the user has clicked.
identify_region(event)identify_row(event, exclude_index = False, allow_end = True)identify_column(event, exclude_header = False, allow_end = True)cut(self, event = None)
copy(self, event = None)
paste(self, event = None)
delete(self, event = None)
undo(self, event = None)
edit_cell(self, event = None, dropdown = False)To change the colors of individual cells, rows or columns use the functions listed under highlighting cells.
For the colors of specific parts of the table such as gridlines and backgrounds use the function set_options(), arguments can be found here. Most of the set_options() arguments are the same as the sheet initialization arguments.
Otherwise you can change the theme using the below function.
change_theme(theme = "light blue", redraw = True)-
theme(str) options (themes) arelight blue,light green,dark,dark blueanddark green.
-
bgandfgarguments use either a tkinter color or a hexstrcolor. - Highlighting cells, rows or columns will also change the colors of dropdown boxes and check boxes.
highlight_cells(row = 0, column = 0, cells = [], canvas = "table", bg = None, fg = None, redraw = True, overwrite = True)- Setting
overwritetoFalseallows a previously setfgto be kept while setting a newbgor vice versa.
dehighlight_cells(row = 0, column = 0, cells = [], canvas = "table", all_ = False, redraw = True)get_highlighted_cells(canvas = "table")highlight_rows(rows = [], bg = None, fg = None, highlight_index = True, redraw = True, end_of_screen = False, overwrite = True)-
end_of_screenwhenTruemakes the row highlight go past the last column line if there is any room there. - Setting
overwritetoFalseallows a previously setfgto be kept while setting a newbgor vice versa.
highlight_columns(columns = [], bg = None, fg = None, highlight_header = True, redraw = True, overwrite = True)- Setting
overwritetoFalseallows a previously setfgto be kept while setting a newbgor vice versa.
dehighlight_all()dehighlight_rows(rows = [], redraw = True)dehighlight_columns(columns = [], redraw = True)-
newfontarguments require a three tuple e.g.("Arial", 12, "normal") -
alignarguments (str) options arew,eorcenter.
font(newfont = None, reset_row_positions = True)header_font(newfont = None)align(align = None, redraw = True)header_align(align = None, redraw = True)row_index_align(align = None, redraw = True)align_rows(rows = [], align = "global", align_index = False, redraw = True)- Use argument
"all"forrowse.g.align_rows("all")to clear all specific row alignments.
align_columns(columns = [], align = "global", align_header = False, redraw = True)- Use argument
"all"forcolumnse.g.align_columns("all")to clear all specific column alignments.
align_cells(row = 0, column = 0, cells = [], align = "global", redraw = True)- Use argument
"all"forrowe.g.align_cells("all")to clear all specific cell alignments.
align_header(columns = [], align = "global", redraw = True)align_index(rows = [], align = "global", redraw = True)get_cell_alignments()get_row_alignments()get_column_alignments()set_options(auto_resize_columns)-
auto_resize_columns(int,None) if set as anintthe columns will automatically resize to fit the width of the window, theintvalue being the minimum of each column in pixels.
set_options(auto_resize_rows)-
auto_resize_rows(int,None) if set as anintthe rows will automatically resize to fit the height of the window, theintvalue being the minimum height of each row in pixels.
default_column_width(width = None)-
width(int).
default_row_height(height = None)-
height(int,str) use a numericalstrfor number of lines e.g."3"for a height that fits 3 lines orintfor pixels.
default_header_height(height = None)-
height(int,str) use a numericalstrfor number of lines e.g."3"for a height that fits 3 lines orintfor pixels.
set_cell_size_to_text(row, column, only_set_if_too_small = False, redraw = True)set_all_cell_sizes_to_text(redraw = True)get_column_widths(canvas_positions = False)-
canvas_positions(bool) gets the actual canvas x coordinates of column lines.
get_row_heights(canvas_positions = False)-
canvas_positions(bool) gets the actual canvas y coordinates of row lines.
Set all column widths to specific width in pixels (int) or leave None to set to cell text sizes for each column.
set_all_column_widths(width = None, only_set_if_too_small = False, redraw = True, recreate_selection_boxes = True)Set all row heights to specific height in pixels (int) or leave None to set to cell text sizes for each row.
set_all_row_heights(height = None, only_set_if_too_small = False, redraw = True, recreate_selection_boxes = True)column_width(column = None, width = None, only_set_if_too_small = False, redraw = True)set_column_widths(column_widths = None, canvas_positions = False, reset = False, verify = False)set_width_of_index_to_text(text = None)-
text(str,None) provide astrto set the width to or useNoneto set it to existing values in the index.
set_height_of_header_to_text(text = None)-
text(str,None) provide astrto set the height to or useNoneto set it to existing values in the header.
row_height(row = None, height = None, only_set_if_too_small = False, redraw = True)set_row_heights(row_heights = None, canvas_positions = False, reset = False, verify = False)delete_row_position(idx, deselect_all = False)insert_row_position(idx = "end", height = None, deselect_all = False, redraw = False)insert_row_positions(idx = "end", heights = None, deselect_all = False, redraw = False)sheet_display_dimensions(total_rows = None, total_columns = None)move_row_position(row, moveto)delete_column_position(idx, deselect_all = False)insert_column_position(idx = "end", width = None, deselect_all = False, redraw = False)insert_column_positions(idx = "end", widths = None, deselect_all = False, redraw = False)move_column_position(column, moveto)get_example_canvas_column_widths(total_cols = None)get_example_canvas_row_heights(total_rows = None)verify_row_heights(row_heights, canvas_positions = False)verify_column_widths(column_widths, canvas_positions = False)get_currently_selected()- Returns
namedtupleof(row, column, type_)e.g.(0, 0, "column")-
type_can be"row","column"or"cell"
-
Usage example below:
currently_selected = self.sheet.get_currently_selected()
if currently_selected:
row = currently_selected.row
column = currently_selected.column
type_ = currently_selected.type_get_selected_rows(get_cells = False, get_cells_as_rows = False, return_tuple = False)get_selected_columns(get_cells = False, get_cells_as_columns = False, return_tuple = False)get_selected_cells(get_rows = False, get_columns = False, sort_by_row = False, sort_by_column = False)get_all_selection_boxes()get_all_selection_boxes_with_types()cell_selected(r, c)row_selected(r)column_selected(c)anything_selected(exclude_columns = False, exclude_rows = False, exclude_cells = False)all_selected()get_ctrl_x_c_boxes()get_selected_min_max()- returns
(min_y, min_x, max_y, max_x)of any selections including rows/columns.
set_currently_selected(row, column, type_ = "cell", selection_binding = True)-
type_(str) either"cell","row"or"column". -
selection_bindingifTrueruns extra bindings selection function if one has been specified usingextra_bindings().
select_row(row, redraw = True)select_column(column, redraw = True)select_cell(row, column, redraw = True)select_all(redraw = True, run_binding_func = True)move_down()add_cell_selection(row, column, redraw = True, run_binding_func = True, set_as_current = True)add_row_selection(row, redraw = True, run_binding_func = True, set_as_current = True)add_column_selection(column, redraw = True, run_binding_func = True, set_as_current = True)toggle_select_cell(row, column, add_selection = True, redraw = True, run_binding_func = True, set_as_current = True)toggle_select_row(row, add_selection = True, redraw = True, run_binding_func = True, set_as_current = True)toggle_select_column(column, add_selection = True, redraw = True, run_binding_func = True, set_as_current = True)create_selection_box(r1, c1, r2, c2, type_ = "cells")recreate_all_selection_boxes()deselect(row = None, column = None, cell = None, redraw = True)sync_scroll(widget: object)- Sync scroll positions between
Sheets, may or may not work with other widgets. Uses scrollbar positions.
Example usage, syncing two sheets:
self.sheet1.sync_scroll(self.sheet2)
self.sheet1.sync_scroll(self.sheet3)Example usage, syncing three sheets:
# syncs sheet 1 and 2 between each other
self.sheet1.sync_scroll(self.sheet2)
# syncs sheet 1 and 3 between each other
self.sheet1.sync_scroll(self.sheet3)
# syncs sheet 2 and 3 between each other
self.sheet2.sync_scroll(self.sheet3)unsync_scroll(widget: None | Sheet = None)- Leaving
widgetasNoneunsyncs all previously synced widgets.
see(row = 0, column = 0, keep_yscroll = False, keep_xscroll = False, bottom_right_corner = False, check_cell_visibility = True)cell_visible(r, c)cell_completely_visible(r, c, seperate_axes = False)-
separate_axesreturns tuple of bools e.g.(cell y axis is visible, cell x axis is visible)
set_xview(position, option = "moveto")set_yview(position, option = "moveto")get_xview()get_yview()set_view(x_args, y_args)move_down()readonly_rows(rows = [], readonly = True, redraw = True)readonly_columns(columns = [], readonly = True, redraw = True)readonly_cells(row = 0, column = 0, cells = [], readonly = True, redraw = True)readonly_header(columns = [], readonly = True, redraw = True)readonly_index(rows = [], readonly = True, redraw = True)display_columns(columns = None,
all_columns_displayed = None,
reset_col_positions = True,
refresh = False,
redraw = False,
deselect_all = True,
**kwargs)-
columns(int,iterable,"all") are the columns to be displayed, omit the columns to be hidden. - Use argument
Truewithall_columns_displayedto display all columns, useFalseto display only the columns you've set using thecolumnsarg. - You can also use the keyword argument
all_displayedinstead ofall_columns_displayed. - Example usage to display all columns:
sheet.display_columns("all"). - Example usage to display specific columns only:
sheet.display_columns([2, 4, 7], all_displayed = False).
all_columns_displayed(a = None)-
a(bool,None) Either set by usingboolor get by leavingNonee.g.all_columns_displayed().
hide_columns(columns = set(),
redraw = True,
deselect_all = True)-
NOTE:
columns(int) uses displayed column indexes, not data indexes. In other words the indexes of the columns displayed on the screen are the ones that are hidden, this is useful when uses in conjunction withget_selected_columns().
display_rows(rows = None,
all_rows_displayed = None,
reset_col_positions = True,
refresh = False,
redraw = False,
deselect_all = True,
**kwargs)-
rows(int,iterable,"all") are the rows to be displayed, omit the rows to be hidden. - Use argument
Truewithall_rows_displayedto display all rows, useFalseto display only the rows you've set using therowsarg. - You can also use the keyword argument
all_displayedinstead ofall_rows_displayed. - Example usage to display all rows:
sheet.display_rows("all"). - Example usage to display specific rows only:
sheet.display_rows([2, 4, 7], all_displayed = False). - This is a very simple example of row filtering using this function.
all_rows_displayed(a = None)-
a(bool,None) Either set by usingboolor get by leavingNonee.g.all_rows_displayed().
hide_rows(rows = set(),
redraw = True,
deselect_all = True)-
NOTE:
rows(int) uses displayed row indexes, not data indexes. In other words the indexes of the rows displayed on the screen are the ones that are hidden, this is useful when uses in conjunction withget_selected_rows().
hide(canvas = "all")-
canvas(str) options areall,row_index,header,top_left,x_scrollbar,y_scrollbar-
allhides the entire table and is the default.
-
show(canvas = "all")-
canvas(str) options areall,row_index,header,top_left,x_scrollbar,y_scrollbar-
allshows the entire table and is the default.
-
open_cell(ignore_existing_editor = True)- Function utilises the currently selected cell in the main table, even if a column/row is selected, to open a non selected cell first use
set_currently_selected()to set the cell to open.
open_header_cell(ignore_existing_editor = True)- Also uses currently selected cell, which you can set with
set_currently_selected().
open_index_cell(ignore_existing_editor = True)- Also uses currently selected cell, which you can set with
set_currently_selected().
set_text_editor_value(text = "", r = None, c = None)destroy_text_editor(event = None)get_text_editor_widget(event = None)bind_key_text_editor(key, function)unbind_key_text_editor(key)When using the functions to create dropdown boxes these are the default arguments:
values = [],
set_value = None,
state = "normal",
redraw = True,
selection_function = None,
modified_function = None,
search_function = dropdown_search_function,
validate_input = True,
text = NoneNotes:
- Use
selection_function/modified_functionlike soselection_function = my_function_name. The function you use needs at least one argument because tksheet will send information to your function about the triggered dropdown. - When a user selects an item from the dropdown box the sheet will set the underlying cells data to the selected item, to bind this event use either the
selection_functionargument or see the functionextra_bindings()with binding"end_edit_cell"here.
Arguments:
-
valuesare the values to appear when the dropdown box is popped open. -
statedetermines whether or not there is also an editable text window at the top of the dropdown box when it is open. -
redrawrefreshes the sheet so the newly created box is visible. -
selection_functioncan be used to trigger a specific function when an item from the dropdown box is selected, if you are using the aboveextra_bindings()as well it will also be triggered but after this function. e.g.selection_function = my_function_name -
modified_functioncan be used to trigger a specific function when thestateof the box is set to"normal"and there is an editable text window and a change of the text in that window has occurred. Note that this function occurs before the dropdown boxes search feature. -
search_function(None,callable) sets the function that will be used to search the dropdown boxes values upon a dropdown text editor modified event when the dropdowns state isnormal. Set toNoneto disable the search feature or use your own function with the following keyword arguments:(search_for, data):and make it return an row number (e.g. select and see the first value would be0) if positive andNoneif negative. -
validate_input(bool) whenTruewill not allow cut, paste, delete or cell editor to input values to cell which are not in the dropdown boxes values. -
text(None,str) can be set to something other thanNoneto always display over whatever value is in the cell, this is useful when you want to display a Header name over a dropdown box selection.
Box creation functions:
create_dropdown(r = 0, c = 0, *args, **kwargs)
dropdown_cell(r = 0, c = 0, *args, **kwargs)-
randc(int,"all") can be set to"all"orint.
dropdown_row(r = 0, *args, **kwargs)-
r(int,"all",iterable) can be set to"all",intor anyiterableofints.
dropdown_column(c = 0, *args, **kwargs)-
c(int,"all",iterable) can be set to"all",intor anyiterableofints.
dropdown_sheet(*args, **kwargs)- Sets the entire sheet to always have a dropdown box in every cell with the specified arguments.
create_index_dropdown(r = 0, *args, **kwargs)-
r(int,None,iterable) useNoneto set the entire index to always having dropdown boxes with the chosen args/kwargs.
create_header_dropdown(c = 0, *args, **kwargs)-
c(int,None,iterable) useNoneto set the entire header to always having dropdown boxes with the chosen args/kwargs.
Examples:
# dropdown boxes all the way down column index 5
sheet.dropdown_column(5, values = ["ON", "OFF"])
# dropdown boxes all the way across rows 0 and 1
sheet.dropdown_row(range(2), values = ["1", "2", "3"])
# headers always have dropdown boxes with the same values
sheet.create_header_dropdown(c = None, values = ["val 1", "val 2"])get_dropdown_values(r = 0, c = 0)get_header_dropdown_values(c = 0)get_index_dropdown_values(r = 0)set_dropdown_values(r = 0, c = 0, set_existing_dropdown = False, values = [], set_value = None)set_header_dropdown_values(c = 0, set_existing_dropdown = False, values = [], set_value = None)set_index_dropdown_values(r = 0, set_existing_dropdown = False, values = [], set_value = None)-
set_existing_dropdownifTruetakes priority overrandcand sets the values of the last popped open dropdown box (if one one is popped open, if not then anExceptionis raised). -
values(list,tuple) -
set_value(str,None) if notNonewill try to set the value of the chosen cell to given argument.
dropdown_functions(r, c, selection_function = "", modified_function = "")header_dropdown_functions(c, selection_function = "", modified_function = "")index_dropdown_functions(r, selection_function = "", modified_function = "")delete_dropdown(r = 0, c = 0)
delete_cell_dropdown(r = 0, c = 0)- Deletes dropdown boxes created by
create_dropdown()/dropdown_cell(). -
randc(int,"all").
delete_row_dropdown(r = 0)- Deletes dropdown boxes created by
dropdown_row(). -
r(int,"all",iterable).
delete_column_dropdown(c = 0)- Deletes dropdown boxes created by
dropdown_column(). -
c(int,"all",iterable).
delete_sheet_dropdown()- Deletes dropdown boxes created by
dropdown_sheet().
delete_index_dropdown(r = 0)- Deletes dropdown boxes created by
create_header_dropdown(). -
r(int,"all",None). UseNoneto delete dropdowns created usingNone.
delete_header_dropdown(c = 0)- Deletes dropdown boxes created by
create_header_dropdown(). -
c(int,"all",None). UseNoneto delete dropdowns created usingNone.
get_dropdowns()get_header_dropdowns()get_index_dropdowns()Returns:
{(row int, column int): {'values': values,
'window': "no dropdown open", #the actual frame object if one exists
'canvas_id': "no dropdown open", #the canvas id of the frame object if one exists
'select_function': selection_function,
'modified_function': modified_function,
'state': state,
'text': text}}-
Note: This dictionary will also contain a key named
"dropdown"if you have useddropdown_sheet()/create_index_dropdown(None)/create_header_dropdown(None).
open_dropdown(r, c)open_header_dropdown(c)open_index_dropdown(r)close_dropdown(r, c)close_header_dropdown(c)close_index_dropdown(r)- Also destroys any opened text editor windows.
When using the functions to create checkboxes these are the default arguments:
checked = False,
state = "normal",
redraw = False,
check_function = None,
text = ""Notes:
- Use
check_functionlike socheck_function = my_function_name. The function you use needs at least one argument because when the checkbox is clicked it will send information to your function about the clicked checkbox. - Use
highlight_cells()or rows or columns to change the color of the checkbox. - Check boxes are always left aligned despite any align settings.
Arguments:
-
randc(int,str) can be set to"all". -
checkedis the initial creation value to set the box to. -
textdisplays text next to the checkbox in the cell, but will not be used as data, data will either beTrueorFalse. -
check_functioncan be used to trigger a function when the user clicks a checkbox. -
statecan be"normal"or"disabled". If"disabled"then color will be same as table grid lines, else it will be the cells text color.
Box creation functions:
create_checkbox(r = 0, c = 0, *args, **kwargs)
checkbox_cell(r = 0, c = 0, *args, **kwargs)-
randc(int,"all") can be set to"all"orint.
checkbox_row(r = 0, *args, **kwargs)-
r(int,"all",iterable) can be set to"all",intor anyiterableofints.
checkbox_column(c = 0, *args, **kwargs)-
c(int,"all",iterable) can be set to"all",intor anyiterableofints.
checkbox_sheet(*args, **kwargs)- Sets the entire sheet to always have a checkboxbox in every cell with the specified arguments.
create_index_checkbox(r = 0, *args, **kwargs)-
r(int,None,iterable) useNoneto set the entire index to always having checkboxes with the chosen args/kwargs.
create_header_checkbox(c = 0, *args, **kwargs)-
c(int,None,iterable) useNoneto set the entire header to always having checkboxes boxes with the chosen args/kwargs.
Examples:
# boxes all the way down column index 5
sheet.checkbox_column(5, text = "Enabled", check_function = my_function)
# boxes all the way across rows 0 and 1
sheet.checkbox_row(range(2), text = "Row Checkbox" checked = True)
# headers always have boxes with the same values
sheet.create_header_checkbox(c = None, text = "Header Checkbox")click_checkbox(r, c, checked = None)click_header_checkbox(c, checked = None)click_index_checkbox(r, checked = None)get_checkboxes()get_header_checkboxes()get_index_checkboxes()delete_checkbox(r = 0, c = 0)
delete_cell_checkbox(r = 0, c = 0)- Deletes checkboxes created by
create_checkbox()/checkbox_cell(). -
randc(int,"all").
delete_row_checkbox(r = 0)- Deletes checkboxes created by
checkbox_row(). -
r(int,"all",iterable).
delete_column_checkbox(c = 0)- Deletes checkboxes created by
checkbox_column(). -
c(int,"all",iterable).
delete_sheet_checkbox()- Deletes checkboxes created by
checkbox_sheet().
delete_index_checkbox(r = 0)- Deletes checkboxes created by
create_header_checkbox(). -
r(int,"all",None). UseNoneto delete checkboxes created usingNone.
delete_header_checkbox(c = 0)- Deletes checkboxes created by
create_header_checkbox(). -
c(int,"all",None). UseNoneto delete checkboxes created usingNone.
checkbox(r,
c,
checked = None,
state = None,
check_function = "",
text = None)header_checkbox(c,
checked = None,
state = None,
check_function = "",
text = None)index_checkbox(r,
checked = None,
state = None,
check_function = "",
text = None)- If any arguments are not default they will be set for the chosen checkbox.
- If all arguments are default a dictionary of all the checkboxes information will be returned.
By default tksheet stores all user inputted data as strings and while tksheet can store and display any datatype with a __str__() method this has some obvious limitations.
Cell formatting aims to provide greater functionality when working with different datatypes and provide strict typing for the sheet. With formatting you can convert sheet data and user input to a specific datatype.
Additionally, formatting also provides a function for displaying data on the table GUI (as a rounded float for example) and logic for handling invalid and missing data.
tksheet has several basic built-in formatters and provides functionality for creating your own custom formats as well.
A demonstration of all the built-in and custom formatters can be found here.
- When applying multiple overlapping formats with e.g. a formatted cell which overlaps a formatted row, the priority is as follows:
- Cell formats first.
- Row formats second.
- Column formats third.
- Sheet format (using
format_sheet()) last.
-
Cell formatting will effectively override
validate_input = Trueon cells with dropdown boxes. -
When getting data take careful note of the
get_displayedoptions, as these are the difference between getting the actual formatted data and what is simply displayed on the table GUI.
format_cell(r, c, formatter_options = {}, formatter_class = None, **kwargs)Notes:
-
format_cell()usingallwill not make added cells (such as with a sheet expanding paste or right click insert rows) formatted. For that you will have to useformat_row()/format_column()/format_sheet().
Arguments:
-
r(intor"all") the row index to apply the formatter to. -
c(intor"all") the column index to apply the formatter to. -
formatter_options(dict) a dictionary of keyword options/arguements to pass to the formatter. -
formatter_class(class) in case you want to use a custom class to store functions and information as opposed to using the built-in methods. -
**kwargsany additional keyword options/arguements to pass to the formatter.
delete_cell_format(r = "all", c = "all", clear_values = False)- Using
"all"will not clear formats set byformat_row()/format_column(). -
r(intor"all") the row index to remove the cell formats from. -
c(intor"all") the column index to remove the cell formats from. -
clear_values(bool) if true, the cell values will be set to"".
format_row(r, formatter_options = {}, formatter_class = None, **kwargs)-
r(int,Iterable[int]or"all") the row index to apply the formatter to. -
formatter_options(dict) a dictionary of keyword options/arguements to pass to the formatter. -
formatter_class(class) in case you want to use a custom class to store functions and information as opposed to using the built-in methods. -
**kwargsany additional keyword options/arguements to pass to the formatter.
delete_row_format(r = "all", clear_values = False)- Using
"all"will not clear formats set byformat_sheet(). -
r(int,Iterable[int]or"all") the row index to remove the cell formats from. -
clear_values(bool) if true, the cell values will be set to"".
format_column(c, formatter_options = {}, formatter_class = None, **kwargs)-
c(int,Iterable[int]or"all") the column index to apply the formatter to. -
formatter_options(dict) a dictionary of keyword options/arguements to pass to the formatter. -
formatter_class(class) in case you want to use a custom class to store functions and information as opposed to using the built-in methods. -
**kwargsany additional keyword options/arguements to pass to the formatter.
delete_column_format(c = "all", clear_values = False)- Using
"all"will not clear formats set byformat_sheet(). -
c(int,Iterable[int]or"all") the column index to remove the cell formats from. -
clear_values(bool) if true, the cell values will be set to"".
format_sheet(formatter_options = {}, formatter_class = None, **kwargs)-
formatter_options(dict) a dictionary of keyword options/arguements to pass to the formatter. -
formatter_class(class) in case you want to use a custom class to store functions and information as opposed to using the built-in methods. -
**kwargsany additional keyword options/arguements to pass to the formatter.
delete_sheet_format(clear_values = False)-
clear_values(bool) if true, all the sheets cell values will be set to"".
delete_all_formatting(clear_values = False)-
clear_values(bool) if true, all the sheets cell values will be set to"".
reapply_formatting()- Useful if you have manually changed the entire sheets data using
sheet.MT.data =and want to reformat the sheet using any existing formatting you have set.
tksheet provides a number of in-built formatters, in addition to the base formatter function. These formatters are designed to provide a range of functionality for different datatypes. The following table lists the available formatters and their options.
formatter(datatypes,
format_function,
to_str_function = to_str,
invalid_value = "NA",
nullable = True,
pre_format_function = None,
post_format_function = None,
clipboard_function = None,
**kwargs)This is the generic formatter options interface. You can use this to create your own custom formatters. The following options are available. Note that all these options can also be passed to the format_cell() function as keyword arguments and are available as attributes for all formatters. You can provide functions of your own creation for all the below arguments which take functions if you require.
-
datatypes(list) a list of datatypes that the formatter will accept. For example,datatypes = [int, float]will accept integers and floats. -
format_function(function) a function that takes a string and returns a value of the desired datatype. For example,format_function = intwill convert a string to an integer. -
to_str_function(function) a function that takes a value of the desired datatype and returns a string. This determines how the formatter displays its data on the table. For example,to_str_function = strwill convert an integer to a string. Defaults totksheet.to_str. -
invalid_value(any) the value to return if the input string is invalid. For example,invalid_value = "NA"will return "NA" if the input string is invalid. -
nullable(bool) if true, the formatter will acceptNoneas a valid input. -
pre_format_function(function) a function that takes a input string and returns a string. This function is called before theformat_functionand can be used to modify the input string before it is converted to the desired datatype. This can be useful if you want to strip out unwanted characters or convert a string to a different format before converting it to the desired datatype. -
post_format_function(function) a function that takes a value which might not be of the desired datatype, e.g.Noneif the cell is nullable and empty and if successful returns a value of the desired datatype or if not successful returns the input value. This function is called after theformat_functionand can be used to modify the output value after it is converted to the desired datatype. This can be useful if you want to round a float for example. -
clipboard_function(function) a function that takes a value of the desired datatype and returns a string. This function is called when the cell value is copied to the clipboard. This can be useful if you want to convert a value to a different format before it is copied to the clipboard. -
**kwargsany additional keyword options/arguements to pass to the formatter. These keyword arguments will be passed to theformat_function,to_str_function, and theclipboard_function. These can be useful if you want to specifiy any additional formatting options, such as the number of decimal places to round to.
int_formatter(datatypes = int,
format_function = to_int,
to_str_function = to_str,
invalid_value = "NaN",
**kwargs,
):The int_formatter is the basic configuration for a simple interger formatter.
-
format_function(function) a function that takes a string and returns anint. By default, this is set to the in-builttksheet.to_int. This function will always convert float-likes to its floor, for example"5.9"will be converted to5. -
to_str_function(function) By default, this is set to the in-builttksheet.to_str, which is a very basic function that will displace the default string representation of the value.
Usage:
sheet.format_cell(0, 0, formatter_options = tksheet.int_formatter())float_formatter(datatypes = float,
format_function = to_float,
to_str_function = float_to_str,
invalid_value = "NaN",
decimals = 2,
**kwargs
)The float_formatter is the basic configuration for a simple float formatter. It will always round float-likes to the specified number of decimal places, for example "5.999" will be converted to "6.0" if decimals = 1.
-
format_function(function) a function that takes a string and returns afloat. By default, this is set to the in-builttksheet.to_float. This function will always convert percentages to their decimal equivalent, for example"5%"will be converted to0.05. -
to_str_function(function) By default, this is set to the in-builttksheet.float_to_str, which will display the float to the specified number of decimal places. -
decimals(int,None) the number of decimal places to round to. Defaults to2.
Usage:
sheet.format_cell(0, 0, formatter_options = tksheet.float_formatter(decimals = None)) # A float formatter with maximum float() decimal placespercentage_formatter(datatypes = float,
format_function = to_float,
to_str_function = percentage_to_str,
invalid_value = "NaN",
decimals = 0,
**kwargs,
)The percentage_formatter is the basic configuration for a simple percentage formatter. It will always round float-likes as a percentage to the specified number of decimal places, for example "5.999%" will be converted to "6.0%" if decimals = 1.
-
format_function(function) a function that takes a string and returns afloat. By default, this is set to the in-builttksheet.to_float. This function will always convert percentages to their decimal equivalent, for example"5%"will be converted to0.05. -
to_str_function(function) By default, this is set to the in-builttksheet.percentage_to_str, which will display the float as a percentage to the specified number of decimal places. For example,0.05will be displayed as"5.0%". -
decimals(int) the number of decimal places to round to. Defaults to0.
Usage:
sheet.format_cell(0, 0, formatter_options = tksheet.percentage_formatter(decimals = 1)) # A percentage formatter with 1 decimal placebool_formatter(datatypes = bool,
format_function = to_bool,
to_str_function = bool_to_str,
invalid_value = "NA",
truthy = truthy,
falsy = falsy,
**kwargs,
)-
format_function(function) a function that takes a string and returns abool. By default, this is set to the in-builttksheet.to_bool. -
to_str_function(function) By default, this is set to the in-builttksheet.bool_to_str, which will display the boolean as"True"or"False". -
truthy(set) a set of values that will be converted toTrue. Defaults to the in-builttksheet.truthy. -
falsy(set) a set of values that will be converted toFalse. Defaults to the in-builttksheet.falsy.
Usage:
# A bool formatter with custom truthy and falsy values to account for aussie and kiwi slang
sheet.format_cell(0, 0, formatter_options = tksheet.bool_formatter(truthy = tksheet.truthy | {"nah yeah"}, falsy = tksheet.falsy | {"yeah nah"}))tksheet is at the moment a dependency free library and so doesn't include a datetime parser as is.
You can however very easily make a datetime parser if you are willing to install a third-party package. Recommended are:
Both of these packages have a very comprehensive datetime parser which can be used to create a custom datetime formatter for tksheet.
Below is a simple example of how you might create a custom datetime formatter using the dateutil package.
from tksheet import *
from datetime import datetime, date
from dateutil.parser import parse
def to_local_datetime(dt, **kwargs):
'''
Our custom format_function, converts a string or a date to a datetime object in the local timezone.
'''
if isinstance(dt, datetime):
pass # Do nothing
elif isinstance(dt, date):
dt = datetime(dt.year, dt.month, dt.day) # Always good to account for unexpected inputs
else:
try:
dt = parser.parse(dt)
except:
raise ValueError(f"Could not parse {dt} as a datetime")
if dt.tzinfo is None:
dt = dt.replace(tzinfo = tzlocal()) # If no timezone is specified, assume local timezone
dt = dt.astimezone(tzlocal()) # Convert to local timezone
return dt
def datetime_to_str(dt, **kwargs):
'''
Our custom to_str_function, converts a datetime object to a string with a format that can be specfied in kwargs.
'''
return dt.strftime(kwargs['format'])
# Now we can create our custom formatter dictionary from the generic formatter interface in tksheet
datetime_formatter = formatter(datatypes = datetime,
format_function = to_local_datetime,
to_str_function = datetime_to_str,
invalid_value = "NaT",
format = "%d/%m/%Y %H:%M:%S",
)
# From here we can pass our datetime_formatter into format_cells() just like any other formatterFor those wanting even more customisation of their formatters you also have the option of creating a custom formatter class. This is a more advanced topic and is not covered here, but it's recommended to create a new class which is a subclass of the tksheet.Formatter class and overriding the methods you would like to customise. This custom class can then be passed into the format_cells() formatter_class argument.
The list of key word arguments available for set_options() are as follows, see here as a guide for what arguments to use.
auto_resize_columns
auto_resize_rows
set_cell_sizes_on_zoom
to_clipboard_delimiter
to_clipboard_quotechar
to_clipboard_lineterminator
from_clipboard_delimiters
show_dropdown_borders
edit_cell_validation
show_default_header_for_empty
show_default_index_for_empty
enable_edit_cell_auto_resize
selected_rows_to_end_of_window
horizontal_grid_to_end_of_window
vertical_grid_to_end_of_window
page_up_down_select_row
expand_sheet_if_paste_too_big
paste_insert_column_limit
paste_insert_row_limit
arrow_key_down_right_scroll_page
display_selected_fg_over_highlights
empty_horizontal
empty_vertical
show_horizontal_grid
show_vertical_grid
top_left_fg_highlight
auto_resize_default_row_index
font
default_header
default_row_index
header_font
show_selected_cells_border
theme
max_colwidth
max_row_height
max_header_height
max_row_width
header_height
row_height
column_width
header_bg
header_border_fg
header_grid_fg
header_fg
header_selected_cells_bg
header_selected_cells_fg
header_hidden_columns_expander_bg
index_bg
index_border_fg
index_grid_fg
index_fg
index_selected_cells_bg
index_selected_cells_fg
index_hidden_rows_expander_bg
top_left_bg
top_left_fg
frame_bg
table_bg
table_grid_fg
table_fg
table_selected_cells_border_fg
table_selected_cells_bg
table_selected_cells_fg
resizing_line_fg
drag_and_drop_bg
outline_thickness
outline_color
header_selected_columns_bg
header_selected_columns_fg
index_selected_rows_bg
index_selected_rows_fg
table_selected_rows_border_fg
table_selected_rows_bg
table_selected_rows_fg
table_selected_columns_border_fg
table_selected_columns_bg
table_selected_columns_fg
popup_menu_font
popup_menu_fg
popup_menu_bg
popup_menu_highlight_bg
popup_menu_highlight_fg
row_drag_and_drop_perform
column_drag_and_drop_perform
redrawGet internal storage dictionary of highlights, readonly cells, dropdowns etc.
get_cell_options(canvas = "table")Delete any formats, alignments, dropdown boxes, checkboxes, highlights etc. that are larger than the sheets currently held data, includes row index and header in measurement of dimensions.
delete_out_of_bounds_options()Delete all alignments, dropdown boxes, checkboxes, highlights etc.
reset_all_options()get_frame_y(y)get_frame_x(x)Flash a dashed box of chosen dimensions.
show_ctrl_outline(canvas = "table", start_cell = (0, 0), end_cell = (1, 1))Reset table undo storage.
reset_undos()Refresh the table.
redraw(redraw_header = True, redraw_row_index = True)Refresh the table.
refresh(redraw_header = True, redraw_row_index = True)Using pandas library, requires additional libraries:
pandasopenpyxl
from tksheet import Sheet
import tkinter as tk
import pandas as pd
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 = pd.read_excel("excel_file.xlsx", # filepath here
#sheet_name = "sheet1", # optional sheet name here
engine = "openpyxl",
header = None).values.tolist())
self.sheet.enable_bindings()
self.frame.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.grid(row = 0, column = 0, sticky = "nswe")
app = demo()
app.mainloop()This is to demonstrate adding your own commands to the in-built right click popup menu (or how you might start making your own right click menu functionality) and also validating text editor input. In this demonstration the validation removes spaces from user input.
from tksheet import Sheet
import tkinter as tk
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}\nnewline1\nnewline2" for c in range(50)] for r in range(500)])
self.sheet.enable_bindings("single_select",
"drag_select",
"edit_cell",
"select_all",
"column_select",
"row_select",
"column_width_resize",
"double_click_column_resize",
"arrowkeys",
"row_height_resize",
"double_click_row_resize",
"right_click_popup_menu",
"rc_select")
self.sheet.extra_bindings([("begin_edit_cell", self.begin_edit_cell),
("end_edit_cell", self.end_edit_cell)])
self.sheet.popup_menu_add_command("Say Hello", self.new_right_click_button)
self.frame.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.grid(row = 0, column = 0, sticky = "nswe")
def new_right_click_button(self, event = None):
print ("Hello World!")
def begin_edit_cell(self, event = None):
return event.text
def end_edit_cell(self, event = None):
# remove spaces from user input
if event.text is not None:
return event.text.replace(" ", "")
app = demo()
app.mainloop()- If you want a totally new right click menu you can use
self.sheet.bind("<3>", <function>)with atk.Menuof your own design (right click is<2>on MacOS) and don't use"right_click_popup_menu"withenable_bindings().
This is to demonstrate displaying what the user has selected in the sheet.
from tksheet import Sheet
import tkinter as tk
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}\nnewline1\nnewline2" for c in range(50)] for r in range(500)])
self.sheet.enable_bindings()
self.sheet.extra_bindings([("all_select_events", self.sheet_select_event)])
self.show_selections = tk.Label(self)
self.frame.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.grid(row = 0, column = 0, sticky = "nswe")
self.show_selections.grid(row = 1, column = 0, sticky = "nswe")
def sheet_select_event(self, event = None):
try:
len(event)
except:
return
try:
if event[0] == "select_cell":
self.show_selections.config(text = f"Cells: ({event[1] + 1},{event[2] + 1}) : ({event[1] + 1},{event[2] + 1})")
elif "cells" in event[0]:
self.show_selections.config(text = f"Cells: ({event.selectionboxes[0] + 1},{event.selectionboxes[1] + 1}) : ({event.selectionboxes[2]},{event.selectionboxes[3]})")
elif event[0] == "select_column":
self.show_selections.config(text = f"Columns: {event[1] + 1} : {event[1] + 1}")
elif "columns" in event[0]:
self.show_selections.config(text = f"Columns: {event[1][0] + 1} : {event[1][-1] + 1}")
elif event[0] == "select_row":
self.show_selections.config(text = f"Rows: {event[1] + 1} : {event[1] + 1}")
elif "rows" in event[0]:
self.show_selections.config(text = f"Rows: {event[1][0] + 1} : {event[1][-1] + 1}")
else:
self.show_selections.config(text = "")
except:
self.show_selections.config(text = "")
app = demo()
app.mainloop()This is to demonstrate some simple customization to make a different sort of widget (a list box).
from tksheet import Sheet
import tkinter as tk
class Sheet_Listbox(Sheet):
def __init__(self,
parent,
values = []):
Sheet.__init__(self,
parent = parent,
show_horizontal_grid = False,
show_vertical_grid = False,
show_header = False,
show_row_index = False,
show_top_left = False,
empty_horizontal = 0,
empty_vertical = 0)
if values:
self.values(values)
def values(self, values = []):
self.set_sheet_data([[v] for v in values],
reset_col_positions = False,
reset_row_positions = False,
redraw = False,
verify = False)
self.set_all_cell_sizes_to_text()
class demo(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.grid_columnconfigure(0,
weight = 1)
self.grid_rowconfigure(0,
weight = 1)
self.listbox = Sheet_Listbox(self,
values = [f"_________ Item {i} _________" for i in range(2000)])
self.listbox.grid(row = 0,
column = 0,
sticky = "nswe")
#self.listbox.values([f"new values {i}" for i in range(50)]) set values
app = demo()
app.mainloop()A very simple demonstration of row filtering using header dropdown boxes.
from tksheet import Sheet
import tkinter as tk
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.data = ([["3", "c", "z"],
["1", "a", "x"],
["1", "b", "y"],
["2", "b", "y"],
["2", "c", "z"]])
self.sheet = Sheet(self.frame,
data = self.data,
theme = "dark",
height = 700,
width = 1100)
self.sheet.enable_bindings("copy",
"rc_select",
"arrowkeys",
"double_click_column_resize",
"column_width_resize",
"column_select",
"row_select",
"drag_select",
"single_select",
"select_all")
self.frame.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.create_header_dropdown(c = 0,
values = ["all", "1", "2", "3"],
set_value = "all",
selection_function = self.header_dropdown_selected,
text = "Header A Name")
self.sheet.create_header_dropdown(c = 1,
values = ["all", "a", "b", "c"],
set_value = "all",
selection_function = self.header_dropdown_selected,
text = "Header B Name")
self.sheet.create_header_dropdown(c = 2,
values = ["all", "x", "y", "z"],
set_value = "all",
selection_function = self.header_dropdown_selected,
text = "Header C Name")
def header_dropdown_selected(self, event = None):
hdrs = self.sheet.headers()
# this function is run before header cell data is set by dropdown selection
# so we have to get the new value from the event
hdrs[event.column] = event.text
if all(dd == "all" for dd in hdrs):
self.sheet.display_rows("all")
else:
rows = [rn for rn, row in enumerate(self.data) if all(row[c] == e or e == "all" for c, e in enumerate(hdrs))]
self.sheet.display_rows(rows = rows,
all_displayed = False)
self.sheet.redraw()
app = demo()
app.mainloop()The code used to make a screenshot for the readme file.
from tksheet import Sheet
import tkinter as tk
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,
expand_sheet_if_paste_too_big = True,
empty_horizontal = 0,
empty_vertical = 0,
align = "w",
header_align = "c",
data = [[f"Row {r}, Column {c}\nnewline 1\nnewline 2" for c in range(6)] for r in range(21)],
headers = ["Dropdown Column", "Checkbox Column", "Center Aligned Column", "East Aligned Column", "", ""],
theme = "black",
height = 520,
width = 930)
self.sheet.enable_bindings("all", "edit_index", "edit header")
self.sheet.popup_menu_add_command("Hide Rows", self.hide_rows, table_menu = False, header_menu = False, empty_space_menu = False)
self.sheet.popup_menu_add_command("Show All Rows", self.show_rows, table_menu = False, header_menu = False, empty_space_menu = False)
self.sheet.popup_menu_add_command("Hide Columns", self.hide_columns, table_menu = False, index_menu = False, empty_space_menu = False)
self.sheet.popup_menu_add_command("Show All Columns", self.show_columns, table_menu = False, index_menu = False, empty_space_menu = False)
self.frame.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.grid(row = 0, column = 0, sticky = "nswe")
colors = ("#509f56",
"#64a85b",
"#78b160",
"#8cba66",
"#a0c36c",
"#b4cc71",
"#c8d576",
"#dcde7c",
"#f0e782",
"#ffec87",
"#ffe182",
"#ffdc7d",
"#ffd77b",
"#ffc873",
"#ffb469",
"#fea05f",
"#fc8c55",
"#fb784b",
"#fa6441",
"#f85037")
self.sheet.align_columns(columns = 2, align = "c")
self.sheet.align_columns(columns = 3, align = "e")
self.sheet.create_dropdown(r = "all",
c = 0,
values = ["Dropdown"] + [f"{i}" for i in range(15)])
self.sheet.create_checkbox(r = "all", c = 1, checked = True, text = "Checkbox")
self.sheet.create_header_dropdown(c = 0, values = ["Header Dropdown"] + [f"{i}" for i in range(15)])
self.sheet.create_header_checkbox(c = 1, checked = True, text = "Header Checkbox")
self.sheet.align_cells(5, 0, align = "c")
self.sheet.highlight_cells(5, 0, bg = "gray50", fg = "blue")
self.sheet.highlight_cells(17, canvas = "index", bg = "yellow", fg = "black")
self.sheet.highlight_cells(12, 1, bg = "gray90", fg = "purple")
for r in range(len(colors)):
self.sheet.highlight_cells(row = r,
column = 3,
fg = colors[r])
self.sheet.highlight_cells(row = r,
column = 4,
bg = colors[r],
fg = "black")
self.sheet.highlight_cells(row = r,
column = 5,
bg = colors[r],
fg = "purple")
self.sheet.highlight_cells(column = 5,
canvas = "header",
bg = "white",
fg = "purple")
self.sheet.set_all_column_widths()
self.sheet.extra_bindings("all", self.all_extra_bindings)
def hide_rows(self, event = None):
rows = self.sheet.get_selected_rows()
if rows:
self.sheet.hide_rows(rows)
def show_rows(self, event = None):
self.sheet.display_rows("all", redraw = True)
def hide_columns(self, event = None):
columns = self.sheet.get_selected_columns()
if columns:
self.sheet.hide_columns(columns)
def show_columns(self, event = None):
self.sheet.display_columns("all", redraw = True)
def all_extra_bindings(self, event = None):
#print (event)
try:
if hasattr(event, 'text'):
return event.text
except:
pass
app = demo()
app.mainloop()To both load a csv file and save tksheet data as a csv file not including headers and index.
from tksheet import Sheet
import tkinter as tk
from tkinter import filedialog
import csv
from os.path import normpath
import io
class demo(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.withdraw()
self.title("tksheet")
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)])
self.sheet.enable_bindings("all", "edit_header", "edit_index")
self.frame.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.popup_menu_add_command("Open csv", self.open_csv)
self.sheet.popup_menu_add_command("Save sheet", self.save_sheet)
self.sheet.set_all_cell_sizes_to_text()
self.sheet.change_theme("light green")
# center the window and unhide
self.update_idletasks()
w = self.winfo_screenwidth() - 20
h = self.winfo_screenheight() - 70
size = (900, 500)
x = (w/2 - size[0]/2)
y = h/2 - size[1]/2
self.geometry("%dx%d+%d+%d" % (size + ((w/2 - size[0]/2), h/2 - size[1]/2)))
self.deiconify()
def save_sheet(self):
filepath = filedialog.asksaveasfilename(parent = self,
title = "Save sheet as",
filetypes = [('CSV File','.csv'),
('TSV File','.tsv')],
defaultextension = ".csv",
confirmoverwrite = True)
if not filepath or not filepath.lower().endswith((".csv", ".tsv")):
return
try:
with open(normpath(filepath), "w", newline = "", encoding = "utf-8") as fh:
writer = csv.writer(fh,
dialect = csv.excel if filepath.lower().endswith(".csv") else csv.excel_tab,
lineterminator = "\n")
writer.writerows(self.sheet.get_sheet_data(get_header = False, get_index = False))
except:
return
def open_csv(self):
filepath = filedialog.askopenfilename(parent = self, title = "Select a csv file")
if not filepath or not filepath.lower().endswith((".csv", ".tsv")):
return
try:
with open(normpath(filepath), "r") as filehandle:
filedata = filehandle.read()
self.sheet.set_sheet_data([r for r in csv.reader(io.StringIO(filedata),
dialect = csv.Sniffer().sniff(filedata),
skipinitialspace = False)])
except:
return
app = demo()
app.mainloop()from tksheet import *
import tkinter as tk
from datetime import datetime, date, timedelta, time
from dateutil import parser, tz
from math import ceil
import re
date_replace = re.compile('|'.join(['\(', '\)', '\[', '\]', '\<', '\>']))
# --------------------- Custom formatter methods ---------------------
def round_up(x):
try: # might not be a number if empty
return float(ceil(x))
except:
return x
def only_numeric(s):
return ''.join(n for n in f"{s}" if n.isnumeric() or n == '.')
def convert_to_local_datetime(dt: str, **kwargs):
if isinstance(dt, datetime):
pass
elif isinstance(dt, date):
dt = datetime(dt.year, dt.month, dt.day)
else:
if isinstance(dt, str):
dt = date_replace.sub("", dt)
try:
dt = parser.parse(dt)
except:
raise ValueError(f"Could not parse {dt} as a datetime")
if dt.tzinfo is None:
dt.replace(tzinfo = tz.tzlocal())
dt = dt.astimezone(tz.tzlocal())
return dt.replace(tzinfo = None)
def datetime_to_string(dt: datetime, **kwargs):
return dt.strftime('%d %b, %Y, %H:%M:%S')
# --------------------- Custom Formatter with additional kwargs ---------------------
def custom_datetime_to_str(dt: datetime, **kwargs):
return dt.strftime(kwargs['format'])
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,
empty_vertical = 0,
empty_horizontal = 0,
data = [[f"{r}"]*11 for r in range(20)]
)
self.sheet.enable_bindings()
self.frame.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.grid(row = 0, column = 0, sticky = "nswe")
self.sheet.headers(['Non-Nullable Float Cell\n1 decimals places',
'Float Cell',
'Int Cell',
'Bool Cell',
'Percentage Cell\n0 decimal places',
'Custom Datetime Cell',
'Custom Datetime Cell\nCustom Format String',
'Float Cell that\nrounds up',
'Float cell that\n strips non-numeric',
'Dropdown Over Nullable\nPercentage Cell',
'Percentage Cell\n2 decimal places'])
# ---------- Some examples of cell formatting --------
self.sheet.format_cell('all', 0, formatter_options = float_formatter(nullable = False))
self.sheet.format_cell('all', 1, formatter_options = float_formatter())
self.sheet.format_cell('all', 2, formatter_options = int_formatter())
self.sheet.format_cell('all', 3, formatter_options = bool_formatter(truthy = truthy | {"nah yeah"}, falsy = falsy | {"yeah nah"}))
self.sheet.format_cell('all', 4, formatter_options = percentage_formatter())
# ---------------- Custom Formatters -----------------
# Custom using generic formatter interface
self.sheet.format_cell('all', 5, formatter_options = formatter(datatypes = datetime,
format_function = convert_to_local_datetime,
to_str_function = datetime_to_string,
nullable = False,
invalid_value = 'NaT',
))
# Custom format
self.sheet.format_cell('all', 6, datatypes = datetime,
format_function = convert_to_local_datetime,
to_str_function = custom_datetime_to_str,
nullable = True,
invalid_value = 'NaT',
format = '(%Y-%m-%d) %H:%M %p'
)
# Unique cell behaviour using the post_conversion_function
self.sheet.format_cell('all', 7, formatter_options = float_formatter(post_format_function = round_up))
self.sheet.format_cell('all', 8, formatter_options = float_formatter(), pre_format_function = only_numeric)
self.sheet.create_dropdown('all', 9, values = ['', '104%', .24, "300%", 'not a number'], set_value = 1)
self.sheet.format_cell('all', 9, formatter_options = percentage_formatter(), decimals = 0)
self.sheet.format_cell('all', 10, formatter_options = percentage_formatter(decimals = 5))
app = demo()
app.mainloop()Welcome and thank you for your interest in tksheet!
-
Adaptable rather than comprehensive: Prioritizes adaptability over comprehensiveness, providing essential features that can be easily extended or customized based on specific needs. This approach allows for flexibility in integrating tksheet into different projects and workflows.
-
Lightweight and performant: Aims to provide a lightweight solution for creating spreadsheet-like functionality in tkinter applications, without additional dependencies and with a focus on efficiency and performance.
tksheet is designed to only use built-in Python libraries (without third-party dependencies). Please ensure that your contributions do not introduce any new dependencies outside of Python's built-in libraries.
tksheet is released under the MIT License. You can find the full text of the license here.
By contributing to the tksheet project, you agree to license your contributions under the same MIT License. Please make sure to read and understand the terms and conditions of the license before contributing.
To contribute, please follow these steps:
- Fork the tksheet repository.
- If you are working on a new feature, create a new branch for your contribution. Use a descriptive name for the branch that reflects the feature you're working on.
- Make your changes in your local branch, following the code style and conventions established in the project.
- Test your changes thoroughly to ensure they do not introduce any new bugs or issues.
- Submit a pull request to the
mainbranch of the tksheet repository, including a clear title and detailed description of your changes. Pull requests ideally should include a small but comprehensive demonstration of the feature you are adding. - Don't forget to update the documentation!
Note: If you're submitting a bugfix, it's generally preferred to submit it directly to the relevant branch, rather than creating a separate branch.
Got a question that hasn't been answered in the closed issues or is missing from the documentation? please follow these guidelines:
- Submit your question as an issue in the Issues tab.
- Provide a clear and concise description of your question, including any relevant details or examples that can help us understand your query better.
Please use the Issues tab to report any issues or ask for assistance.
When submitting an issue, please follow these guidelines:
- Check the existing issues to see if a similar bug or question has already been reported or discussed.
- If reporting a bug, provide a minimal example that can reproduce the issue, including any relevant code, error messages, and steps to reproduce.
- If asking a question or seeking help, provide a clear and concise description of your question or issue, including any relevant details or examples that can help people understand your query better.
- Include any relevant screenshots or gifs that can visually illustrate the issue or your question.
If you have an idea for a new feature, improvement or change, please follow these guidelines:
- Submit your suggestion as an issue in the Issues tab.
- Include a clear and concise description of your idea, including any relevant details, screenshots, or mock-ups that can help contributors understand your suggestion better.
- You're also welcomed to become a contributor yourself and help implement your idea!