- Notifications
You must be signed in to change notification settings - Fork57
Version 7
tksheetis a Python tkinter table and treeview widget written in pure python.- It is licensed under theMIT license.
- It works by using tkinter canvases and moving lines, text and rectangles around for only the visible portion of the table.
- If you are using a version of tksheet that is older than
7.0.0then you will need the documentationhere instead.- In tksheet versions >=
7.0.2the current version will be at the top of the file__init__.py.
- In tksheet versions >=
- Word wrap - Tabs and multiple spaces are rendered as a single space.
- Mac OS has both
<2>and<3>bound for right click. - When using
edit_validation()to validate cell edits and pasting into the sheet:- If the sheets rows are expanded then the row numbers under the key
rowandlocare data indexes whereas the column numbers are displayed indexes. - If the sheets columns are expanded then the column numbers under the key
columnandlocare data indexes whereas the row numbers are displayed indexes. - This is only relevant when there are hidden rows or columns and you're using
edit_validation()and you're using the event data keysrow,columnorlocin your boundedit_validation()function and you're using paste and the sheet can be expanded by paste.
- If the sheets rows are expanded then the row numbers under the key
- There may be some issues with toggle select mode and deselection.
Some examples of things that are not possible with tksheet:
- Due to the limitations of the Tkinter Canvas right-to-left (RTL) languages are not supported.
- Cell merging.
- Changing font for individual cells.
- Mouse drag copy cells.
- Cell highlight borders.
- At the present time the type hinting in tksheet is only meant to serve as a guide and not to be used with type checkers.
tksheet is available through PyPi (Python package index) and can be installed by using Pip through the command linepip install tksheet
#To install using pippipinstalltksheet#To update using pippipinstalltksheet--upgrade
Alternatively you can download the source code and inside the tksheet directory where thepyproject.toml file is located use the command linepip install -e .
- Versions<
7.0.0require a Python version of3.7or higher. - Versions>=
7.0.0require a Python version of3.8or higher.
Like other tkinter widgets you need only theSheet()s parent as an argument to initialize aSheet() 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 aSheet() widget
fromtksheetimportSheetimporttkinterastkclassdemo(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"forcinrange(50)]forrinrange(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 to demonstrate some of tksheets functionality:
- The functions which return the Sheet itself (have
-> Sheet) can be chained with other Sheet functions. - The functions which return a Span (have
-> Span) can be chained with other Span functions.
fromtksheetimportSheet,num2alphaimporttkinterastkclassdemo(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)# create an instance of Sheet()self.sheet=Sheet(# set the Sheets parent widgetself.frame,# optional: set the Sheets data at initializationdata=[[f"Row{r}, Column{c}\nnewline1\nnewline2"forcinrange(20)]forrinrange(100)],theme="light green",height=520,width=1000, )# enable various bindingsself.sheet.enable_bindings("all","edit_index","edit_header")# set a user edit validation function# AND bind all sheet modification events to a function# chained as two functions# more information at:# #bind-and-validate-user-cell-editsself.sheet.edit_validation(self.validate_edits).bind("<<SheetModified>>",self.sheet_modified)# add some new commands to the in-built right click menu# setting dataself.sheet.popup_menu_add_command("Say Hello",self.say_hello,index_menu=False,header_menu=False,empty_space_menu=False, )# getting dataself.sheet.popup_menu_add_command("Print some data",self.print_data,empty_space_menu=False, )# overwrite Sheet dataself.sheet.popup_menu_add_command("Reset Sheet data",self.reset)# set the headerself.sheet.popup_menu_add_command("Set header data",self.set_header,table_menu=False,index_menu=False,empty_space_menu=False, )# set the indexself.sheet.popup_menu_add_command("Set index data",self.set_index,table_menu=False,header_menu=False,empty_space_menu=False, )self.frame.grid(row=0,column=0,sticky="nswe")self.sheet.grid(row=0,column=0,sticky="nswe")defvalidate_edits(self,event):# print (event)ifevent.eventname.endswith("header"):returnevent.value+" edited header"elifevent.eventname.endswith("index"):returnevent.value+" edited index"else:ifnotevent.value:return"EMPTY"returnevent.value[:3]defsay_hello(self):current_selection=self.sheet.get_currently_selected()ifcurrent_selection:box= (current_selection.row,current_selection.column)# set cell data, end user Undo enabled# more information at:# #setting-sheet-dataself.sheet[box].options(undo=True).data="Hello World!"# highlight the cell for 2 secondsself.highlight_area(box)defprint_data(self):forboxinself.sheet.get_all_selection_boxes():# get user selected area sheet data# more information at:# #getting-sheet-datadata=self.sheet[box].dataforrowindata:print(row)defreset(self):# overwrites sheet data, more information at:# #setting-sheet-dataself.sheet.set_sheet_data([[f"Row{r}, Column{c}\nnewline1\nnewline2"forcinrange(20)]forrinrange(100)])# reset header and indexself.sheet.headers([])self.sheet.index([])defset_header(self):self.sheet.headers( [f"Header{(letter:=num2alpha(i))} -{i+1}\nHeader{letter} 2nd line!"foriinrange(20)] )defset_index(self):self.sheet.set_index_width()self.sheet.row_index( [f"Index{(letter:=num2alpha(i))} -{i+1}\nIndex{letter} 2nd line!"foriinrange(100)] )defsheet_modified(self,event):# uncomment below if you want to take a look at the event object# print ("The sheet was modified! Event object:")# for k, v in event.items():# print (k, ":", v)# print ("\n")# otherwise more information at:# #event-data# highlight the modified cells brieflyifevent.eventname.startswith("move"):forboxinself.sheet.get_all_selection_boxes():self.highlight_area(box)else:forboxinevent.selection_boxes:self.highlight_area(box)defhighlight_area(self,box,time=800):# highlighting an area of the sheet# more information at:# #highlighting-cellsself.sheet[box].bg="indianred1"self.after(time,lambda:self.clear_highlight(box))defclear_highlight(self,box):self.sheet[box].dehighlight()app=demo()app.mainloop()
These are all the initialization parameters, the only required argument is the sheetsparent, every other parameter has default arguments.
def__init__(parent:tk.Misc,name:str="!sheet",show_table:bool=True,show_top_left:bool|None=None,show_row_index:bool=True,show_header:bool=True,show_x_scrollbar:bool=True,show_y_scrollbar:bool=True,width:int|None=None,height:int|None=None,headers:None|list[Any]=None,header:None|list[Any]=None,row_index:None|list[Any]=None,index:None|list[Any]=None,default_header:Literal["letters","numbers","both"]|None="letters",default_row_index:Literal["letters","numbers","both"]|None="numbers",data_reference:None|Sequence[Sequence[Any]]=None,data:None|Sequence[Sequence[Any]]=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") # noqa: E501startup_select:tuple[int,int,str]|tuple[int,int,int,int,str]=None,startup_focus:bool=True,total_columns:int|None=None,total_rows:int|None=None,default_column_width:int=120,default_header_height:str|int="1",default_row_index_width:int=70,default_row_height:str|int="1",min_column_width:int=1,max_column_width:float=float("inf"),max_row_height:float=float("inf"),max_header_height:float=float("inf"),max_index_width:float=float("inf"),after_redraw_time_ms:int=16,set_all_heights_and_widths:bool=False,zoom:int=100,align:str="nw",header_align:str="n",row_index_align:str|None=None,index_align:str="n",displayed_columns:list[int]|None=None,all_columns_displayed:bool=True,displayed_rows:list[int]|None=None,all_rows_displayed:bool=True,to_clipboard_dialect:csv.Dialect=csv.excel_tab,to_clipboard_delimiter:str="\t",to_clipboard_quotechar:str='"',to_clipboard_lineterminator:str="\n",from_clipboard_delimiters:list[str]|str="\t",show_default_header_for_empty:bool=True,show_default_index_for_empty:bool=True,page_up_down_select_row:bool=True,paste_can_expand_x:bool=False,paste_can_expand_y:bool=False,paste_insert_column_limit:int|None=None,paste_insert_row_limit:int|None=None,show_dropdown_borders:bool=False,arrow_key_down_right_scroll_page:bool=False,cell_auto_resize_enabled:bool=True,auto_resize_row_index:bool|Literal["empty"]="empty",auto_resize_columns:int|None=None,auto_resize_rows:int|None=None,set_cell_sizes_on_zoom:bool=False,font:tuple[str,int,str]=FontTuple("Calibri",13ifUSER_OS=="darwin"else11,"normal", ),header_font:tuple[str,int,str]=FontTuple("Calibri",13ifUSER_OS=="darwin"else11,"normal", ),index_font:tuple[str,int,str]=FontTuple("Calibri",13ifUSER_OS=="darwin"else11,"normal", ),# currently has no effectpopup_menu_font:tuple[str,int,str]=FontTuple("Calibri",13ifUSER_OS=="darwin"else11,"normal", ),max_undos:int=30,column_drag_and_drop_perform:bool=True,row_drag_and_drop_perform:bool=True,empty_horizontal:int=50,empty_vertical:int=50,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,edit_cell_tab:Literal["right","down",""]="right",edit_cell_return:Literal["right","down",""]="down",editor_del_key:Literal["forward","backward",""]="forward",treeview:bool=False,treeview_indent:str|int="2",rounded_boxes:bool=True,alternate_color:str="",allow_cell_overflow:bool=False,# "" no wrap, "w" word wrap, "c" char wraptable_wrap:Literal["","w","c"]="c",index_wrap:Literal["","w","c"]="c",header_wrap:Literal["","w","c"]="c",sort_key:Callable=natural_sort_key,tooltips:bool=False,user_can_create_notes:bool=False,note_corners:bool=False,tooltip_width:int=210,tooltip_height:int=210,tooltip_hover_delay:int=1200,# colorsoutline_thickness:int=0,theme:str="light blue",outline_color:str=theme_light_blue["outline_color"],frame_bg:str=theme_light_blue["table_bg"],popup_menu_fg:str=theme_light_blue["popup_menu_fg"],popup_menu_bg:str=theme_light_blue["popup_menu_bg"],popup_menu_highlight_bg:str=theme_light_blue["popup_menu_highlight_bg"],popup_menu_highlight_fg:str=theme_light_blue["popup_menu_highlight_fg"],table_grid_fg:str=theme_light_blue["table_grid_fg"],table_bg:str=theme_light_blue["table_bg"],table_fg:str=theme_light_blue["table_fg"],table_editor_bg:str=theme_light_blue["table_editor_bg"],table_editor_fg:str=theme_light_blue["table_editor_fg"],table_editor_select_bg:str=theme_light_blue["table_editor_select_bg"],table_editor_select_fg:str=theme_light_blue["table_editor_select_fg"],table_selected_box_cells_fg:str=theme_light_blue["table_selected_box_cells_fg"],table_selected_box_rows_fg:str=theme_light_blue["table_selected_box_rows_fg"],table_selected_box_columns_fg:str=theme_light_blue["table_selected_box_columns_fg"],table_selected_cells_border_fg:str=theme_light_blue["table_selected_cells_border_fg"],table_selected_cells_bg:str=theme_light_blue["table_selected_cells_bg"],table_selected_cells_fg:str=theme_light_blue["table_selected_cells_fg"],table_selected_rows_border_fg:str=theme_light_blue["table_selected_rows_border_fg"],table_selected_rows_bg:str=theme_light_blue["table_selected_rows_bg"],table_selected_rows_fg:str=theme_light_blue["table_selected_rows_fg"],table_selected_columns_border_fg:str=theme_light_blue["table_selected_columns_border_fg"],table_selected_columns_bg:str=theme_light_blue["table_selected_columns_bg"],table_selected_columns_fg:str=theme_light_blue["table_selected_columns_fg"],resizing_line_fg:str=theme_light_blue["resizing_line_fg"],drag_and_drop_bg:str=theme_light_blue["drag_and_drop_bg"],index_bg:str=theme_light_blue["index_bg"],index_border_fg:str=theme_light_blue["index_border_fg"],index_grid_fg:str=theme_light_blue["index_grid_fg"],index_fg:str=theme_light_blue["index_fg"],index_editor_bg:str=theme_light_blue["index_editor_bg"],index_editor_fg:str=theme_light_blue["index_editor_fg"],index_editor_select_bg:str=theme_light_blue["index_editor_select_bg"],index_editor_select_fg:str=theme_light_blue["index_editor_select_fg"],index_selected_cells_bg:str=theme_light_blue["index_selected_cells_bg"],index_selected_cells_fg:str=theme_light_blue["index_selected_cells_fg"],index_selected_rows_bg:str=theme_light_blue["index_selected_rows_bg"],index_selected_rows_fg:str=theme_light_blue["index_selected_rows_fg"],index_hidden_rows_expander_bg:str=theme_light_blue["index_hidden_rows_expander_bg"],header_bg:str=theme_light_blue["header_bg"],header_border_fg:str=theme_light_blue["header_border_fg"],header_grid_fg:str=theme_light_blue["header_grid_fg"],header_fg:str=theme_light_blue["header_fg"],header_editor_bg:str=theme_light_blue["header_editor_bg"],header_editor_fg:str=theme_light_blue["header_editor_fg"],header_editor_select_bg:str=theme_light_blue["header_editor_select_bg"],header_editor_select_fg:str=theme_light_blue["header_editor_select_fg"],header_selected_cells_bg:str=theme_light_blue["header_selected_cells_bg"],header_selected_cells_fg:str=theme_light_blue["header_selected_cells_fg"],header_selected_columns_bg:str=theme_light_blue["header_selected_columns_bg"],header_selected_columns_fg:str=theme_light_blue["header_selected_columns_fg"],header_hidden_columns_expander_bg:str=theme_light_blue["header_hidden_columns_expander_bg"],top_left_bg:str=theme_light_blue["top_left_bg"],top_left_fg:str=theme_light_blue["top_left_fg"],top_left_fg_highlight:str=theme_light_blue["top_left_fg_highlight"],vertical_scroll_background:str=theme_light_blue["vertical_scroll_background"],horizontal_scroll_background:str=theme_light_blue["horizontal_scroll_background"],vertical_scroll_troughcolor:str=theme_light_blue["vertical_scroll_troughcolor"],horizontal_scroll_troughcolor:str=theme_light_blue["horizontal_scroll_troughcolor"],vertical_scroll_lightcolor:str=theme_light_blue["vertical_scroll_lightcolor"],horizontal_scroll_lightcolor:str=theme_light_blue["horizontal_scroll_lightcolor"],vertical_scroll_darkcolor:str=theme_light_blue["vertical_scroll_darkcolor"],horizontal_scroll_darkcolor:str=theme_light_blue["horizontal_scroll_darkcolor"],vertical_scroll_relief:str=theme_light_blue["vertical_scroll_relief"],horizontal_scroll_relief:str=theme_light_blue["horizontal_scroll_relief"],vertical_scroll_troughrelief:str=theme_light_blue["vertical_scroll_troughrelief"],horizontal_scroll_troughrelief:str=theme_light_blue["horizontal_scroll_troughrelief"],vertical_scroll_bordercolor:str=theme_light_blue["vertical_scroll_bordercolor"],horizontal_scroll_bordercolor:str=theme_light_blue["horizontal_scroll_bordercolor"],vertical_scroll_active_bg:str=theme_light_blue["vertical_scroll_active_bg"],horizontal_scroll_active_bg:str=theme_light_blue["horizontal_scroll_active_bg"],vertical_scroll_not_active_bg:str=theme_light_blue["vertical_scroll_not_active_bg"],horizontal_scroll_not_active_bg:str=theme_light_blue["horizontal_scroll_not_active_bg"],vertical_scroll_pressed_bg:str=theme_light_blue["vertical_scroll_pressed_bg"],horizontal_scroll_pressed_bg:str=theme_light_blue["horizontal_scroll_pressed_bg"],vertical_scroll_active_fg:str=theme_light_blue["vertical_scroll_active_fg"],horizontal_scroll_active_fg:str=theme_light_blue["horizontal_scroll_active_fg"],vertical_scroll_not_active_fg:str=theme_light_blue["vertical_scroll_not_active_fg"],horizontal_scroll_not_active_fg:str=theme_light_blue["horizontal_scroll_not_active_fg"],vertical_scroll_pressed_fg:str=theme_light_blue["vertical_scroll_pressed_fg"],horizontal_scroll_pressed_fg:str=theme_light_blue["horizontal_scroll_pressed_fg"],vertical_scroll_borderwidth:int=1,horizontal_scroll_borderwidth:int=1,vertical_scroll_gripcount:int=0,horizontal_scroll_gripcount:int=0,scrollbar_theme_inheritance:str="default",scrollbar_show_arrows:bool=True,# changing the arrowsize (width) of the scrollbars# is not working with 'default' theme# use 'clam' theme instead if you want to change the widthvertical_scroll_arrowsize:str|int="",horizontal_scroll_arrowsize:str|int="",**kwargs,)->None
namesetting a name for the sheet is useful when you have multiple sheets and you need to determine which one an event came from.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.startup_selecteither(start row, end row, "rows"),(start column, end column, "rows")or(start row, start column, end row, end column, "cells"). The start/end row/column variables need to beints.auto_resize_row_indexeitherTrue,Falseor"empty"."empty"it will only automatically resize if the row index is empty.Trueit will always automatically resize.Falseit will never automatically resize.
- If
show_selected_cells_borderisFalsethen the colors fortable_selected_box_cells_fg/table_selected_box_rows_fg/table_selected_box_columns_fgwill be used for the currently selected cells background. - Only set
show_top_lefttoTrueif you want to always show the top left rectangle of the sheet. Leave asNoneto only show it when both the index and header are showing. - For help with
treeviewmode seehere.
You can change most of these settings after initialization using theset_options() function.
scrollbar_theme_inheritanceandscrollbar_show_arrowswill only work onSheet()initialization, not withset_options()
To change the colors of individual cells, rows or columns use the functions listed underhighlighting cells.
For the colors of specific parts of the table such as gridlines and backgrounds use the functionset_options(), keyword arguments specific to sheet colors are listed below. All the otherset_options() arguments can be foundhere.
Use a tkinter color or a hex string e.g.
my_sheet_widget.set_options(table_bg="black")my_sheet_widget.set_options(table_bg="#000000")my_sheet_widget.set_options(horizontal_scroll_pressed_bg="red")
set_options(top_left_bgtop_left_fgtop_left_fg_highlighttable_bgtable_grid_fgtable_fgtable_selected_box_cells_fgtable_selected_box_rows_fgtable_selected_box_columns_fgtable_selected_cells_border_fgtable_selected_cells_bgtable_selected_cells_fgtable_selected_rows_border_fgtable_selected_rows_bgtable_selected_rows_fgtable_selected_columns_border_fgtable_selected_columns_bgtable_selected_columns_fgheader_bgheader_border_fgheader_grid_fgheader_fgheader_selected_cells_bgheader_selected_cells_fgheader_selected_columns_bgheader_selected_columns_fgindex_bgindex_border_fgindex_grid_fgindex_fgindex_selected_cells_bgindex_selected_cells_fgindex_selected_rows_bgindex_selected_rows_fgresizing_line_fgdrag_and_drop_bgoutline_thicknessoutline_colorframe_bgpopup_menu_fontpopup_menu_fgpopup_menu_bgpopup_menu_highlight_bgpopup_menu_highlight_fg# scroll barsvertical_scroll_backgroundhorizontal_scroll_backgroundvertical_scroll_troughcolorhorizontal_scroll_troughcolorvertical_scroll_lightcolorhorizontal_scroll_lightcolorvertical_scroll_darkcolorhorizontal_scroll_darkcolorvertical_scroll_bordercolorhorizontal_scroll_bordercolorvertical_scroll_active_bghorizontal_scroll_active_bgvertical_scroll_not_active_bghorizontal_scroll_not_active_bgvertical_scroll_pressed_bghorizontal_scroll_pressed_bgvertical_scroll_active_fghorizontal_scroll_active_fgvertical_scroll_not_active_fghorizontal_scroll_not_active_fgvertical_scroll_pressed_fghorizontal_scroll_pressed_fg)
Otherwise you can change the theme using the below function.
change_theme(theme:str="light blue",redraw:bool=True)->Sheet
theme(str) options (themes) are currently"light blue","light green","dark","black","dark blue"and"dark green".
Scrollbar colors:
The abovefunction and keyword arguments can be used to change the colors of the scroll bars.
Scrollbar relief, size, arrows, etc.
Some scroll bar style options can only be changed onSheet() initialization, others can be changed whenever usingset_options():
- Options that can only be set in the
= Sheet(...)initialization:scrollbar_theme_inheritance: str = "default"- This is which tkinter theme to inherit the new style from, changing the width of the scroll bar might not work with the
"default"theme. If this is the case try using"clam"instead.
- This is which tkinter theme to inherit the new style from, changing the width of the scroll bar might not work with the
scrollbar_show_arrows: bool- When
Falsethe scroll bars arrow buttons on either end will be hidden, this may effect the width of the scroll bar.
- When
- Options that can be set using
set_options()also:vertical_scroll_borderwidth: inthorizontal_scroll_borderwidth: intvertical_scroll_gripcount: inthorizontal_scroll_gripcount: intvertical_scroll_arrowsize: str | inthorizontal_scroll_arrowsize: str | int
For basic alternate row colors in the main table either:
- Use the
Sheet()initialization keyword argumentalternate_color(str) or - Use the
set_options()function with the keyword argumentalternate_color
Examples:
set_options(alternate_color="#E2EAF4")
my_sheet=Sheet(parent,alternate_color="gray80")
Note that any cell, row or column highlights will display over alternate row colors.
Refresh the table.
refresh(redraw_header:bool=True,redraw_row_index:bool=True)->Sheet
Refresh the table.
redraw(redraw_header:bool=True,redraw_row_index:bool=True)->Sheet
Refresh after idle (prevents multiple redraws).
set_refresh_timer(redraw:bool=True,index:bool=True,header:bool=True,)->Sheet
set_options(redraw:bool=True,**kwargs)->Sheet
Key word arguments available forset_options() (values are defaults):
"popup_menu_fg":"#000000","popup_menu_bg":"#FFFFFF","popup_menu_highlight_bg":"#DCDEE0","popup_menu_highlight_fg":"#000000","index_hidden_rows_expander_bg":"#747775","header_hidden_columns_expander_bg":"#747775","header_bg":"#FFFFFF","header_border_fg":"#C4C7C5","header_grid_fg":"#C4C7C5","header_fg":"#444746","header_editor_bg":"#FFFFFF","header_editor_fg":"#444746","header_editor_select_bg":"#cfd1d1","header_editor_select_fg":"#000000","header_selected_cells_bg":"#D3E3FD","header_selected_cells_fg":"black","index_bg":"#FFFFFF","index_border_fg":"#C4C7C5","index_grid_fg":"#C4C7C5","index_fg":"black","index_editor_bg":"#FFFFFF","index_editor_fg":"black","index_editor_select_bg":"#cfd1d1","index_editor_select_fg":"#000000","index_selected_cells_bg":"#D3E3FD","index_selected_cells_fg":"black","top_left_bg":"#F9FBFD","top_left_fg":"#d9d9d9","top_left_fg_highlight":"#747775","table_bg":"#FFFFFF","table_grid_fg":"#E1E1E1","table_fg":"black","table_editor_bg":"#FFFFFF","table_editor_fg":"black","table_editor_select_bg":"#cfd1d1","table_editor_select_fg":"#000000","table_selected_box_cells_fg":"#0B57D0","table_selected_box_rows_fg":"#0B57D0","table_selected_box_columns_fg":"#0B57D0","table_selected_cells_border_fg":"#0B57D0","table_selected_cells_bg":"#E6EFFD","table_selected_cells_fg":"black","resizing_line_fg":"black","drag_and_drop_bg":"#0B57D0","outline_color":"gray2","header_selected_columns_bg":"#0B57D0","header_selected_columns_fg":"#FFFFFF","index_selected_rows_bg":"#0B57D0","index_selected_rows_fg":"#FFFFFF","table_selected_rows_border_fg":"#0B57D0","table_selected_rows_bg":"#E6EFFD","table_selected_rows_fg":"black","table_selected_columns_border_fg":"#0B57D0","table_selected_columns_bg":"#E6EFFD","table_selected_columns_fg":"black","tree_arrow_fg":"black","selected_cells_tree_arrow_fg":"black","selected_rows_tree_arrow_fg":"#FFFFFF","vertical_scroll_background":"#FFFFFF","horizontal_scroll_background":"#FFFFFF","vertical_scroll_troughcolor":"#f9fbfd","horizontal_scroll_troughcolor":"#f9fbfd","vertical_scroll_lightcolor":"#FFFFFF","horizontal_scroll_lightcolor":"#FFFFFF","vertical_scroll_darkcolor":"gray50","horizontal_scroll_darkcolor":"gray50","vertical_scroll_relief":"flat","horizontal_scroll_relief":"flat","vertical_scroll_troughrelief":"flat","horizontal_scroll_troughrelief":"flat","vertical_scroll_bordercolor":"#f9fbfd","horizontal_scroll_bordercolor":"#f9fbfd","vertical_scroll_active_bg":"#bdc1c6","horizontal_scroll_active_bg":"#bdc1c6","vertical_scroll_not_active_bg":"#DADCE0","horizontal_scroll_not_active_bg":"#DADCE0","vertical_scroll_pressed_bg":"#bdc1c6","horizontal_scroll_pressed_bg":"#bdc1c6","vertical_scroll_active_fg":"#bdc1c6","horizontal_scroll_active_fg":"#bdc1c6","vertical_scroll_not_active_fg":"#DADCE0","horizontal_scroll_not_active_fg":"#DADCE0","vertical_scroll_pressed_fg":"#bdc1c6","horizontal_scroll_pressed_fg":"#bdc1c6","popup_menu_font":FontTuple("Calibri",13ifUSER_OS=="darwin"else11,"normal",),"table_font":FontTuple("Calibri",13ifUSER_OS=="darwin"else11,"normal",),"header_font":FontTuple("Calibri",13ifUSER_OS=="darwin"else11,"normal",),"index_font":FontTuple("Calibri",13ifUSER_OS=="darwin"else11,"normal",),# edit header"edit_header_label":"Edit header","edit_header_accelerator":"","edit_header_image":tk.PhotoImage(data=ICON_EDIT),"edit_header_compound":"left",# edit index"edit_index_label":"Edit index","edit_index_accelerator":"","edit_index_image":tk.PhotoImage(data=ICON_EDIT),"edit_index_compound":"left",# edit cell"edit_cell_label":"Edit cell","edit_cell_accelerator":"","edit_cell_image":tk.PhotoImage(data=ICON_EDIT),"edit_cell_compound":"left",# cut"cut_label":"Cut","cut_accelerator":"Ctrl+X","cut_image":tk.PhotoImage(data=ICON_CUT),"cut_compound":"left",# copy"copy_label":"Copy","copy_accelerator":"Ctrl+C","copy_image":tk.PhotoImage(data=ICON_COPY),"copy_compound":"left",# copy plain"copy_plain_label":"Copy text","copy_plain_accelerator":"Ctrl+Insert","copy_plain_image":tk.PhotoImage(data=ICON_COPY),"copy_plain_compound":"left",# paste"paste_label":"Paste","paste_accelerator":"Ctrl+V","paste_image":tk.PhotoImage(data=ICON_PASTE),"paste_compound":"left",# delete"delete_label":"Delete","delete_accelerator":"Del","delete_image":tk.PhotoImage(data=ICON_CLEAR),"delete_compound":"left",# clear contents"clear_contents_label":"Clear contents","clear_contents_accelerator":"Del","clear_contents_image":tk.PhotoImage(data=ICON_CLEAR),"clear_contents_compound":"left",# del columns"delete_columns_label":"Delete columns","delete_columns_accelerator":"","delete_columns_image":tk.PhotoImage(data=ICON_DEL),"delete_columns_compound":"left",# insert columns left"insert_columns_left_label":"Insert columns left","insert_columns_left_accelerator":"","insert_columns_left_image":tk.PhotoImage(data=ICON_ADD),"insert_columns_left_compound":"left",# insert columns right"insert_columns_right_label":"Insert columns right","insert_columns_right_accelerator":"","insert_columns_right_image":tk.PhotoImage(data=ICON_ADD),"insert_columns_right_compound":"left",# insert single column"insert_column_label":"Insert column","insert_column_accelerator":"","insert_column_image":tk.PhotoImage(data=ICON_ADD),"insert_column_compound":"left",# del rows"delete_rows_label":"Delete rows","delete_rows_accelerator":"","delete_rows_image":tk.PhotoImage(data=ICON_DEL),"delete_rows_compound":"left",# insert rows above"insert_rows_above_label":"Insert rows above","insert_rows_above_accelerator":"","insert_rows_above_image":tk.PhotoImage(data=ICON_ADD),"insert_rows_above_compound":"left",# insert rows below"insert_rows_below_label":"Insert rows below","insert_rows_below_accelerator":"","insert_rows_below_image":tk.PhotoImage(data=ICON_ADD),"insert_rows_below_compound":"left",# insert single row"insert_row_label":"Insert row","insert_row_accelerator":"","insert_row_image":tk.PhotoImage(data=ICON_ADD),"insert_row_compound":"left",# sorting# labels"sort_cells_label":"Sort Asc.","sort_cells_x_label":"Sort row-wise Asc.","sort_row_label":"Sort values Asc.","sort_column_label":"Sort values Asc.","sort_rows_label":"Sort rows Asc.","sort_columns_label":"Sort columns Asc.",# reverse labels"sort_cells_reverse_label":"Sort Desc.","sort_cells_x_reverse_label":"Sort row-wise Desc.","sort_row_reverse_label":"Sort values Desc.","sort_column_reverse_label":"Sort values Desc.","sort_rows_reverse_label":"Sort rows Desc.","sort_columns_reverse_label":"Sort columns Desc.",# accelerators"sort_cells_accelerator":"","sort_cells_x_accelerator":"","sort_row_accelerator":"","sort_column_accelerator":"","sort_rows_accelerator":"","sort_columns_accelerator":"",# reverse accelerators"sort_cells_reverse_accelerator":"","sort_cells_x_reverse_accelerator":"","sort_row_reverse_accelerator":"","sort_column_reverse_accelerator":"","sort_rows_reverse_accelerator":"","sort_columns_reverse_accelerator":"",# images"sort_cells_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_cells_x_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_row_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_column_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_rows_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_columns_image":tk.PhotoImage(data=ICON_SORT_ASC),# compounds"sort_cells_compound":"left","sort_cells_x_compound":"left","sort_row_compound":"left","sort_column_compound":"left","sort_rows_compound":"left","sort_columns_compound":"left",# reverse images"sort_cells_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_cells_x_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_row_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_column_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_rows_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_columns_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),# reverse compounds"sort_cells_reverse_compound":"left","sort_cells_x_reverse_compound":"left","sort_row_reverse_compound":"left","sort_column_reverse_compound":"left","sort_rows_reverse_compound":"left","sort_columns_reverse_compound":"left",# select all"select_all_label":"Select all","select_all_accelerator":"Ctrl+A","select_all_image":tk.PhotoImage(data=ICON_SELECT_ALL),"select_all_compound":"left",# undo"undo_label":"Undo","undo_accelerator":"Ctrl+Z","undo_image":tk.PhotoImage(data=ICON_UNDO),"undo_compound":"left",# redo"redo_label":"Redo","redo_accelerator":"Ctrl+Shift+Z","redo_image":tk.PhotoImage(data=ICON_REDO),"redo_compound":"left",# bindings"rc_bindings": ["<2>","<3>"]ifUSER_OS=="darwin"else ["<3>"],"copy_bindings": [f"<{ctrl_key}-c>",f"<{ctrl_key}-C>",],"copy_plain_bindings": [f"<{ctrl_key}-Insert>",],"cut_bindings": [f"<{ctrl_key}-x>",f"<{ctrl_key}-X>",],"paste_bindings": [f"<{ctrl_key}-v>",f"<{ctrl_key}-V>",],"undo_bindings": [f"<{ctrl_key}-z>",f"<{ctrl_key}-Z>",],"redo_bindings": [f"<{ctrl_key}-Shift-z>",f"<{ctrl_key}-Shift-Z>",],"delete_bindings": ["<Delete>",],"select_all_bindings": [f"<{ctrl_key}-a>",f"<{ctrl_key}-A>",f"<{ctrl_key}-Shift-space>",],"select_columns_bindings": ["<Control-space>",],"select_rows_bindings": ["<Shift-space>",],"row_start_bindings": ["<Command-Left>","<Home>",]ifUSER_OS=="darwin"else ["<Home>"],"table_start_bindings": [f"<{ctrl_key}-Home>",],"tab_bindings": ["<Tab>",],"up_bindings": ["<Up>",],"right_bindings": ["<Right>",],"down_bindings": ["<Down>",],"left_bindings": ["<Left>",],"shift_up_bindings": ["<Shift-Up>",],"shift_right_bindings": ["<Shift-Right>",],"shift_down_bindings": ["<Shift-Down>",],"shift_left_bindings": ["<Shift-Left>",],"prior_bindings": ["<Prior>",],"next_bindings": ["<Next>",],"find_bindings": [f"<{ctrl_key}-f>",f"<{ctrl_key}-F>",],"find_next_bindings": [f"<{ctrl_key}-g>",f"<{ctrl_key}-G>",],"find_previous_bindings": [f"<{ctrl_key}-Shift-g>",f"<{ctrl_key}-Shift-G>",],"toggle_replace_bindings": [f"<{ctrl_key}-h>",f"<{ctrl_key}-H>",],"escape_bindings": ["<Escape>",],# other"vertical_scroll_borderwidth":1,"horizontal_scroll_borderwidth":1,"vertical_scroll_gripcount":0,"horizontal_scroll_gripcount":0,"vertical_scroll_arrowsize":"","horizontal_scroll_arrowsize":"","set_cell_sizes_on_zoom":False,"auto_resize_columns":None,"auto_resize_rows":None,"to_clipboard_dialect":csv.excel_tab,"to_clipboard_delimiter":"\t","to_clipboard_quotechar":'"',"to_clipboard_lineterminator":"\n","from_clipboard_delimiters": ["\t"],"show_dropdown_borders":False,"show_default_header_for_empty":True,"show_default_index_for_empty":True,"default_header_height":"1","default_row_height":"1","default_column_width":120,"default_row_index_width":70,"default_row_index":"numbers","default_header":"letters","page_up_down_select_row":True,"paste_can_expand_x":False,"paste_can_expand_y":False,"paste_insert_column_limit":None,"paste_insert_row_limit":None,"arrow_key_down_right_scroll_page":False,"cell_auto_resize_enabled":True,"auto_resize_row_index":True,"max_undos":30,"column_drag_and_drop_perform":True,"row_drag_and_drop_perform":True,"empty_horizontal":50,"empty_vertical":50,"selected_rows_to_end_of_window":False,"horizontal_grid_to_end_of_window":False,"vertical_grid_to_end_of_window":False,"show_vertical_grid":True,"show_horizontal_grid":True,"display_selected_fg_over_highlights":False,"show_selected_cells_border":True,"edit_cell_tab":"right","edit_cell_return":"down","editor_del_key":"forward","treeview":False,"treeview_indent":"2","rounded_boxes":True,"alternate_color":"","allow_cell_overflow":False,"table_wrap":"c","header_wrap":"c","index_wrap":"c","min_column_width":1,"max_column_width":float("inf"),"max_header_height":float("inf"),"max_row_height":float("inf"),"max_index_width":float("inf"),"show_top_left":None,"sort_key":natural_sort_key,"tooltips":False,"user_can_create_notes":False,"note_corners":False,"tooltip_width":int=210,"tooltip_height":int=210,"tooltip_hover_delay":int=1200,
Notes:
- The parameters ending in
_imagetaketk.PhotoImageor an empty string""as types. - The parameters ending in
_compoundtake one of the following:"left", "right", "bottom", "top", "none", None. sort_keyisCallable- a function.- A dictionary can be provided to
set_options()instead of using the keyword arguments, e.g.:
kwargs= {"copy_bindings": ["<Control-g>","<Control-G>", ],"cut_bindings": ["<Control-c>","<Control-C>", ],}sheet.set_options(**kwargs)
set_header_data(value:Any,c:int|None|Iterator=None,redraw:bool=True)->Sheet
value(iterable,int,Any) ifcis left asNonethen it attempts to set the whole header as thevalue(converting a generator to a list). Ifvalueisintit sets the header to display the row with that position.c(iterable,int,None) if bothvalueandcare iterables it assumescis an iterable of positions andvalueis an iterable of values and attempts to set each value to each position. Ifcisintit attempts to set the value at that position.
headers(newheaders:Any=None,index:None|int=None,reset_col_positions:bool=False,show_headers_if_not_sheet:bool=True,redraw:bool=True,)->Any
- 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.
set_index_data(value:Any,r:int|None|Iterator=None,redraw:bool=True)->Sheet
value(iterable,int,Any) ifris left asNonethen it attempts to set the whole index as thevalue(converting a generator to a list). Ifvalueisintit sets the index to display the row with that position.r(iterable,int,None) if bothvalueandrare iterables it assumesris an iterable of positions andvalueis an iterable of values and attempts to set each value to each position. Ifrisintit attempts to set the value at that position.
row_index(newindex:Any=None,index:None|int=None,reset_row_positions:bool=False,show_index_if_not_sheet:bool=True,redraw:bool=True,)->Any
- 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.
You can set table, header and index text wrapping either atSheet() initialization or usingset_options().
Make use of the following parameters:
table_wrapindex_wrapheader_wrap
With one of the following arguments:
""- For no text wrapping."c"- For character wrapping."w"- For word wrapping.
Examples:
# for word wrap at initializationmy_sheet=Sheet(parent,table_wrap="w")# for character wrap using set_options()my_sheet.set_options(table_wrap="c")
This setting only works for cells that are not center (north) aligned. Cell text can be set to overflow adjacent empty cells in the table like so:
Examples:
# for word wrap at initializationmy_sheet=Sheet(parent,allow_cell_overflow=True)# for character wrap using set_options()my_sheet.set_options(allow_cell_overflow=True)
- Set it to
Falseto disable it. - It is only available as a global setting for the table, not on a cell by cell basis.
enable_bindings(*bindings:Binding,menu:bool=True)
Parameters:
bindings(str) options are (rc stands for right click):"all"# enables all bindings withsingle_selectmode, except the bindings that have to be specifically enabled by name."single_select"# normal selection mode"toggle_select"# has issues but to enable a selection mode where cell/row/column selection is toggled"drag_select"# to allow mouse click and drag selection of cells/rows/columns"select_all"# drag_select also enables select_all
"column_drag_and_drop"/"move_columns"# to allow drag and drop of columns"row_drag_and_drop"/"move_rows"# to allow drag and drop of rows"column_select"# to allow column selection"row_select"# to allow row selection"column_width_resize"# for resizing columns"double_click_column_resize"# for resizing columns to row text width"row_width_resize"# to resize the index width"column_height_resize"# to resize the header height"arrowkeys"# all arrowkeys including page up and down"up"# individual arrow key"down"# individual arrow key"left"# individual arrow key"right"# individual arrow key"prior"# page up"next"# page down"row_height_resize"# to resize rows"double_click_row_resize"# for resizing rows to row text height"right_click_popup_menu"/"rc_popup_menu"/"rc_menu"# for the in-built table context menu"rc_select"# for selecting cells using right click"rc_insert_column"# for a menu option to add columns"rc_delete_column"# for a menu option to delete columns"rc_insert_row"# for a menu option to add rows"rc_delete_row"# for a menu option to delete rows"sort_cells""sort_row""sort_column"/"sort_col""sort_rows""sort_columns"/"sort_cols""copy"# for copying to clipboard"cut"# for cutting to clipboard"paste"# for pasting into the table"delete"# for clearing cells with the delete key"undo"# for undo and redo"edit_cell"# allow table cell editing"find"# for a pop-up find window (does not find in index or header)"replace"# additional functionality for the find window, replace and replace all- *
"ctrl_click_select"/"ctrl_select"# for selecting multiple non-adjacent cells/rows/columns - *
"edit_header"# allow header cell editing - *
"edit_index"# allow index cell editing - *has to be specifically enabled - See Notes.
menu(bool) whenTrueadds the related functionality to the in-built popup menu. Only applicable for edit bindings such as Cut, Copy, Paste and Delete which have both a keyboard binding and a menu entry.
Notes:
- You can change the Sheets key bindings for functionality such as copy, paste, up, down etc. Instructions can be foundhere.
- Note that the following functionalities are not enabled using
"all"and have to be specifically enabled:"ctrl_click_select"/"ctrl_select""edit_header""edit_index"
- To allow table expansion when pasting data which doesn't fit in the table use either:
paste_can_expand_x=True,paste_can_expand_y=Truein sheet initialization arguments or the same keyword arguments with the functionset_options().
Example:
sheet.enable_bindings()to enable everything except"ctrl_select","edit_index","edit_header".
disable_bindings(*bindings:Binding)
Notes:
- Uses the same arguments as
enable_bindings().
This function allows you to bindvery specific table functionality to your own functions:
- If you want less specificity in event names you can also bind all sheet modifying events to a single function,see here.
- If you want to validate/modify user cell editssee here.
extra_bindings(bindings:str|list|tuple,func:Callable|None=None,)->Sheet
There are several ways to use this function:
bindingsas astrandfuncas eitherNoneor a function. UsingNoneas an argument forfuncwill effectively unbind the function.extra_bindings("edit_cell", func=my_function)
bindingsas aniterableofstrs andfuncas eitherNoneor a function. UsingNoneas an argument forfuncwill 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.
- For
"end_..."events the bound function is run before the value is set. - To unbind a function either set
funcargument toNoneor leave it as default e.g.extra_bindings("begin_copy")to unbind"begin_copy". - Even though undo/redo edits or adds or deletes rows/columns the bound functions for those actions will not be called. Undo/redo must be specifically bound in order for a function to be called.
bindings (str) options:
Undo/Redo:
"begin_undo", "begin_ctrl_z""ctrl_z", "end_undo", "end_ctrl_z", "undo"
Editing Individual Cells:
"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"
Editing or Copying Multiple Cells:
"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_delete_key", "begin_delete""delete_key", "end_delete", "end_delete_key", "delete""replace_all"
Moving:
"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_sort_cells""sort_cells", "end_sort_cells""begin_sort_rows""sort_rows", "end_sort_rows""begin_sort_columns""sort_columns", "end_sort_columns"
Deleting:
"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"
Adding:
"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", "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", "add_rows"
Resizing rows/columns:
"row_height_resize""column_width_resize"
Selection:
"cell_select""all_select""row_select""column_select""drag_select_cells""drag_select_rows""drag_select_columns""shift_cell_select""shift_row_select""shift_column_select""ctrl_cell_select""ctrl_row_select""ctrl_column_select""deselect"
Event collections:
"all_select_events", "select", "selectevents", "select_events""all_modified_events", "sheetmodified", "sheet_modified" "modified_events", "modified""bind_all""unbind_all"
Further Notes:
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. - For events
"begin_move_columns"/"begin_move_rows"the point where columns/rows will be moved to will be accessible by the key named"value". - For
"begin_edit..."events the bound function must return a value to open the cell editor with, examplehere.
Usingextra_bindings() the function you bind needs to have at least one argument which will receive adict. The values of which can be accessed by dot notation e.g.event.eventname orevent.cells.table:
for (row,column),old_valueinevent.cells.table.items():print (f"R{row}",f"C{column}","Old Value:",old_value)
It has the following layout and keys:
{"eventname":"","sheetname":"","cells": {"table": {},"header": {},"index": {}, },"moved": {"rows": {},"columns": {}, },"added": {"rows": {},"columns": {}, },"deleted": {"rows": {},"columns": {},"header": {},"index": {},"column_widths": {},"row_heights": {},"options": {},"displayed_columns":None,"displayed_rows":None, },"named_spans": {},"selection_boxes": {},"selected":tuple(),"being_selected":tuple(),"data": [],"key":"","value":None,"loc":tuple(),"row":None,"column":None,"resized": {"rows": {},"columns": {}, },"widget":None,}Keys:
A function bound using
extra_bindings()will receive event data with one of the following["eventname"]keys:"begin_ctrl_c""end_ctrl_c""begin_ctrl_x""end_ctrl_x""begin_ctrl_v""end_ctrl_v""begin_delete""end_delete""begin_undo""end_undo""begin_add_columns""end_add_columns""begin_add_rows""end_add_rows""begin_delete_columns""end_delete_columns""begin_delete_rows""end_delete_rows""begin_edit_table""end_edit_table""begin_edit_index""end_edit_index""begin_edit_header""end_edit_header""select""resize"- *
"begin_move_rows" - *
"end_move_rows" - *
"begin_move_columns" - *
"end_move_columns"
*is also used as the event name for sorting rows/columns events.
EventDataDicts will otherwise have one of the following event names:"edit_table"when a user has cut, paste, delete or made any cell edits including using dropdown boxes etc. in the table."edit_index"when a user has edited a index cell."edit_header"when a user has edited a header cell."add_columns"when a user has inserted columns."add_rows"when a user has inserted rows."delete_columns"when a user has deleted columns."delete_rows"when a user has deleted rows."move_columns"when a user has dragged and dropped OR sorted columns."move_rows"when a user has dragged and dropped OR sorted rows."select""resize"
These event names would be used for
"<<SheetModified>>"bound events for example.For events
"begin_move_columns"/"begin_move_rows"the point where columns/rows will be moved to will be under theevent_datakey"value".Key
["sheetname"]is thename given to the sheet widget on initialization, useful if you have multiple sheets to determine which one emitted the event.Key
["cells"]["table"]if any table cells have been modified by cut, paste, delete, cell editors, dropdown boxes, check boxes, undo or redo this will be adictwithtuplekeys of(data row index: int, data column index: int)and the values will be the cell values at that locationprior to the change. Thedictwill be empty if no such changes have taken place.Key
["cells"]["header"]if any header cells have been modified by cell editors, dropdown boxes, check boxes, undo or redo this will be adictwith keys ofint: data column indexand the values will be the cell values at that locationprior to the change. Thedictwill be empty if no such changes have taken place.Key
["cells"]["index"]if any index cells have been modified by cell editors, dropdown boxes, check boxes, undo or redo this will be adictwith keys ofint: data row indexand the values will be the cell values at that locationprior to the change. Thedictwill be empty if no such changes have taken place.Key
["moved"]["rows"]if any rows have been moved by dragging and dropping or undoing/redoing of dragging and dropping rows this will be adictwith the following keys:{"data": {old data index: new data index, ...}, "displayed": {old displayed index: new displayed index, ...}}"data"will be adictwhere the keys are the old data indexes of the rows and the values are the data indexes they have moved to."displayed"will be adictwhere the keys are the old displayed indexes of the rows and the values are the displayed indexes they have moved to.- If no rows have been moved the
dictunder["moved"]["rows"]will be empty. - Note that if there are hidden rows the values for
"data"will include all currently displayed row indexes and their new locations. If required and available, the values under"displayed"include only the directly moved rows, convert to data indexes usingSheet.data_r().
- For events
"begin_move_rows"the point where rows will be moved to will be under theevent_datakey"value".
Key
["moved"]["columns"]if any columns have been moved by dragging and dropping or undoing/redoing of dragging and dropping columns this will be adictwith the following keys:{"data": {old data index: new data index, ...}, "displayed": {old displayed index: new displayed index, ...}}"data"will be adictwhere the keys are the old data indexes of the columns and the values are the data indexes they have moved to."displayed"will be adictwhere the keys are the old displayed indexes of the columns and the values are the displayed indexes they have moved to.- If no columns have been moved the
dictunder["moved"]["columns"]will be empty. - Note that if there are hidden columns the values for
"data"will include all currently displayed column indexes and their new locations. If required and available, the values under"displayed"include only the directly moved columns, convert to data indexes usingSheet.data_c().
- For events
"begin_move_columns"the point where columns will be moved to will be under theevent_datakey"value".
Key
["added"]["rows"]if any rows have been added by the inbuilt popup menu insert rows or by a paste which expands the sheet then this will be adictwith the following keys:{"data_index": int, "displayed_index": int, "num": int, "displayed": []}"data_index"is anintrepresenting the row where the rows were added in the data."displayed_index"is anintrepresenting the displayed table index where the rows were added (which will be different from the data index if there are hidden rows)."displayed"is a copied list of theSheet()s displayed rows immediately prior to the change.- If no rows have been added the
dictwill be empty.
Key
["added"]["columns"]if any columns have been added by the inbuilt popup menu insert columns or by a paste which expands the sheet then this will be adictwith the following keys:{"data_index": int, "displayed_index": int, "num": int, "displayed": []}"data_index"is anintrepresenting the column where the columns were added in the data."displayed_index"is anintrepresenting the displayed table index where the columns were added (which will be different from the data index if there are hidden columns)."displayed"is a copied list of theSheet()s displayed columns immediately prior to the change.- If no columns have been added the
dictwill be empty.
Key
["deleted"]["columns"]if any columns have been deleted by the inbuilt popup menu delete columns or by undoing a paste which added columns then this will be adict. Thisdictwill look like the following:{[column data index]: {[row data index]: cell value, [row data index]: cell value}, [column data index]: {...} ...}- If no columns have been deleted then the
dictvalue for["deleted"]["columns"]will be empty.
Key
["deleted"]["rows"]if any rows have been deleted by the inbuilt popup menu delete rows or by undoing a paste which added rows then this will be adict. Thisdictwill look like the following:{[row data index]: {[column data index]: cell value, [column data index]: cell value}, [row data index]: {...} ...}- If no rows have been deleted then the
dictvalue for["deleted"]["rows"]will be empty.
Key
["deleted"]["header"]if any header values have been deleted by the inbuilt popup menu delete columns or by undoing a paste which added columns and header values then this will be adict. Thisdictwill look like the following:{[column data index]: header cell value, [column data index]: header cell value, ...}- If no columns have been deleted by the mentioned methods then the
dictvalue for["deleted"]["header"]will be empty.
Key
["deleted"]["index"]if any index values have been deleted by the inbuilt popup menu delete rows or by undoing a paste which added rows and index values then this will be adict. Thisdictwill look like the following:{[row data index]: index cell value, [row data index]: index cell value, ...}- If no index values have been deleted by the mentioned methods then the
dictvalue for["deleted"]["index"]will be empty.
Key
["deleted"]["column_widths"]if any columns have been deleted by the inbuilt popup menu delete columns or by undoing a paste which added columns then this will be adict. Thisdictwill look like the following:{[column data index]: column width, [column data index]: column width, ...}- If no columns have been deleted then the
dictvalue for["deleted"]["column_widths"]will be empty.
Key
["deleted"]["row_heights"]if any rows have been deleted by the inbuilt popup menu delete rows or by undoing a paste which added rows then this will be adict. Thisdictwill look like the following:{[row data index]: row height, [row data index]: row height, ...}- If no rows have been deleted then the
dictvalue for["deleted"]["row_heights"]will be empty.
Key
["deleted"]["displayed_columns"]if any columns have been deleted by the inbuilt popup menu delete columns or by undoing a paste which added columns then this will be alist. Thisliststores the displayed columns (the columns that are showing when others are hidden) immediately prior to the change.Key
["deleted"]["displayed_rows"]if any rows have been deleted by the inbuilt popup menu delete rows or by undoing a paste which added rows then this will be alist. Thisliststores the displayed rows (the rows that are showing when others are hidden) immediately prior to the change.Key
["named_spans"]Thisdictserves as storage for theSheet()s named spans. Each value in thedictis a pickledspanobject.Key
["options"]This serves as storage for theSheet()s options such as highlights, formatting, alignments, dropdown boxes, check boxes etc. It is adictwhere the values are the sheets internal cell/row/column optionsdicts.Key
["selection_boxes"]the value of this is all selection boxes on the sheet in the form of adictas shown below:- For every event except
"select"events the selection boxes are those immediately prior to the modification, for"select"events they are the current selection boxes. - The layout is always:
"selection_boxes": {(start row, start column, up to but not including row, up to but not including column): selection box type}.- The row/column indexes are
ints and the selection box type is astreither"cells","rows"or"columns".
- The row/column indexes are
- The
dictwill be empty if there is nothing selected.
- For every event except
Key
["selected"]the value of this when there is something selected on the sheet is anamedtuple. The values of which can be foundhere.- When nothing is selected or the event is not relevant to the currently selected box, such as a resize event it will be an empty
tuple.
- When nothing is selected or the event is not relevant to the currently selected box, such as a resize event it will be an empty
Key
["being_selected"]if any selection box is in the process of being drawn by holding down mouse button 1 and dragging then this will be a tuple with the following layout:(start row, start column, up to but not including row, up to but not including column, selection box type).- The selection box type is a
streither"cells","rows"or"columns".
- The selection box type is a
- If no box is in the process of being created then this will be a an empty
tuple. - See here for an example.
Key
["data"]-dict[tuple[int, int], Any]- changed from only being used by paste, now stores adictof cell coordinates and values that make up a table edit event of more than one cell.Key
["key"]-str- is primarily used for cell edit events where a key press has occurred. For"begin_edit..."events the value is the actual key which was pressed (or"??"for using the mouse to open a cell). It also might be one of the following for end edit events:"Return"- enter key."FocusOut"- the editor or box lost focus, perhaps by mouse clicking elsewhere."Tab"- tab key.
Key
["value"]is used primarily by cell editing events. For"begin_edit..."events it's the value displayed in he text editor when it opens. For"end_edit..."events it's the value in the text editor when it was closed, for example by hittingReturn. It also used by"begin_move_columns"/"begin_move_rows"- the point where columns/rows will be moved to will be under theevent_datakey"value".Key
["loc"]is for cell editing events to show the displayed (not data) coordinates of the event. It will beeither:- A tuple of
(int displayed row index, int displayed column index)in the case of editing table cells. - A single
intin the case of editing index/header cells.
- A tuple of
Key
["row"]is for cell editing events to show the displayed (not data) row numberintof the event. If the event was not a cell editing event or a header cell was edited the value will beNone.Key
["column"]is for cell editing events to show the displayed (not data) column numberintof the event. If the event was not a cell editing event or an index cell was edited the value will beNone.Key
["resized"]["rows"]is for row height resizing events, it will be adictwith the following layout:{int displayed row index: {"old_size": old_height, "new_size": new_height}}.- If no rows have been resized then the value for
["resized"]["rows"]will be an emptydict.
Key
["resized"]["columns"]is for column width resizing events, it will be adictwith the following layout:{int displayed column index: {"old_size": old_width, "new_size": new_width}}.- If no columns have been resized then the value for
["resized"]["columns"]will be an emptydict.
Key
["widget"]will contain the widget which emitted the event, either theMainTable(),ColumnHeaders()orRowIndex()which are alltk.Canvaswidgets.
With these functions you can validate or modify most user sheet edits, includes cut, paste, delete (including column/row clear), dropdown boxes and cell edits.
Edit validation
This function will be called for every cell edit in an action.
edit_validation(func:Callable|None=None)->Sheet
Parameters:
func(Callable,None) must either be a function which will receive a tksheet event dict which looks likethis orNonewhich unbinds the function.
Notes:
- If your bound function returns
Nonethen that specific cell edit will not be performed. - For examples of this function seehere andhere.
Bulk edit validation
This function will be called at the end of an action and delay any edits until after validation.
bulk_table_edit_validation(func:Callable|None=None)->Sheet
Parameters:
func(Callable,None) must either be a function which will receive a tksheet event dict which looks likethis orNonewhich unbinds the function.
Notes:
- See the below example for more information on usage.
Example:
fromtksheetimportSheetimporttkinterastkfromtypingimportAnyclassdemo(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}"forcinrange(3)]forrinrange(3)], )self.sheet.enable_bindings()self.sheet.bulk_table_edit_validation(self.validate)self.frame.grid(row=0,column=0,sticky="nswe")self.sheet.grid(row=0,column=0,sticky="nswe")defvalidate(self,event:dict)->Any:""" Whatever keys and values are left in event["data"] when the function returns are the edits that will be made An example below shows preventing edits if the proposed edit contains a space But you can also modify the values, or add more key, value pairs to event["data"] """not_valid=set()for (r,c),valueinevent.data.items():if" "invalue:not_valid.add((r,c))event.data= {k:vfork,vinevent.data.items()ifknotinnot_valid}app=demo()app.mainloop()
popup_menu_add_command(label:str,func:Callable,table_menu:bool=True,index_menu:bool=True,header_menu:bool=True,empty_space_menu:bool=True,image:tk.PhotoImage|Literal[""]="",compound:Literal["top","bottom","left","right","none"]|None=None,accelerator:str|None=None,)->Sheet
Notes:
- Either creates or overwrites an existing menu command.
Example:
self.sheet.popup_menu_add_command(label="Test insert rows",func=self.my_fn,image=tk.PhotoImage(file="filepath_to_img.png"),compound="left",)
popup_menu_del_command(label:str|None=None)->Sheet
- If
labelisNonethen it removes all.
basic_bindings(enable:bool=False)->Sheet
These functions are links to the Sheets own functionality. Functions such ascut() rely on whatever is currently selected on the Sheet.
cut(event:Any=None)->Sheetcopy(event:Any=None)->Sheetpaste(event:Any=None)->Sheetdelete(event:Any=None)->Sheetundo(event:Any=None)->Sheetredo(event:Any=None)->Sheetzoom_in()->Sheetzoom_out()->Sheet
@propertydefevent()->EventDataDict
- e.g.
last_event_data = sheet.event - Will be empty
EventDataDictif there is no last event.
focus_set(canvas:Literal["table","header","row_index","index","topleft","top_left", ]="table",)->Sheet
- With the
Sheet.bind()function you can bind things in the usual way you would in tkinter and they will bind to all thetksheetcanvases. - There are also the following special
tksheetevents you can bind:
| Binding | Usable withevent_generate() |
|---|---|
"<<SheetModified>>" | - |
"<<SheetRedrawn>>" | - |
"<<SheetSelect>>" | - |
"<<Copy>>" | X |
"<<Cut>>" | X |
"<<Paste>>" | X |
"<<Delete>>" | X |
"<<Undo>>" | X |
"<<Redo>>" | X |
"<<SelectAll>>" | X |
bind(event:str,func:Callable,add:str|None=None,)
Parameters:
addmay or may not work for various bindings depending on whether they are already in use bytksheet.- Note that while a bound event after a paste/undo/redo might have the event name
"edit_table"it also might have added/deleted rows/columns, refer to the docs on the event datadictfor more information. eventthe emitted events are:"<<SheetModified>>"emitted whenever the sheet was modified by the end user by editing cells or adding or deleting rows/columns. The function you bind to this event must be able to receive adictargument which will be the same asthe event data dict but with less specific event names. The possible event names are listed below:"edit_table"when a user has cut, paste, delete or made any cell edits including using dropdown boxes etc. in the table."edit_index"when a user has edited a index cell."edit_header"when a user has edited a header cell."add_columns"when a user has inserted columns."add_rows"when a user has inserted rows."delete_columns"when a user has deleted columns."delete_rows"when a user has deleted rows."move_columns"when a user has dragged and dropped columns."move_rows"when a user has dragged and dropped rows."sort_rows"when rows have been re-ordered by sorting."sort_columns"when columns have been re-ordered by sorting.
"<<SheetRedrawn>>"emitted whenever the sheet GUI was refreshed (redrawn). The data for this event will be different than the usual event data, it is:{"sheetname": name of your sheet, "header": bool True if the header was redrawn, "row_index": bool True if the index was redrawn, "table": bool True if the the table was redrawn}
"<<SheetSelect>>"encompasses all select events and emits the same event as"<<SheetModified>>"but with the event name:"select"."<<Copy>>"emitted when a Sheet copy e.g.<Control-c>was performed and will have theeventname"copy"."<<Cut>>""<<Paste>>""<<Delete>>"emitted when a Sheet delete key function was performed."<<SelectAll>>""<<Undo>>""<<Redo>>"
Example:
# self.sheet_was_modified is your functionself.sheet.bind("<<SheetModified>>",self.sheet_was_modified)
Example forevent_generate():
self.sheet.event_generate("<<Copy>>")
- Tells the sheet to run its copy function.
With this function you can unbind things you have bound using thebind() function.
unbind(binding:str)->Sheet
In this section are instructions to change some of tksheets in-built language and bindings:
- The in-built right click menu.
- The in-built functionality keybindings, such as copy, paste etc.
Please note that due to the limitations of the Tkinter Canvas tksheet doesn’t support right-to-left (RTL) languages.
You can change the labels for tksheets in-built right click popup menu by using theset_options() function with any of the following keyword arguments:
# edit header"edit_header_label":"Edit header","edit_header_accelerator":"","edit_header_image":tk.PhotoImage(data=ICON_EDIT),"edit_header_compound":"left",# edit index"edit_index_label":"Edit index","edit_index_accelerator":"","edit_index_image":tk.PhotoImage(data=ICON_EDIT),"edit_index_compound":"left",# edit cell"edit_cell_label":"Edit cell","edit_cell_accelerator":"","edit_cell_image":tk.PhotoImage(data=ICON_EDIT),"edit_cell_compound":"left",# cut"cut_label":"Cut","cut_accelerator":"Ctrl+X","cut_image":tk.PhotoImage(data=ICON_CUT),"cut_compound":"left",# copy"copy_label":"Copy","copy_accelerator":"Ctrl+C","copy_image":tk.PhotoImage(data=ICON_COPY),"copy_compound":"left",# copy plain"copy_plain_label":"Copy text","copy_plain_accelerator":"Ctrl+Insert","copy_plain_image":tk.PhotoImage(data=ICON_COPY),"copy_plain_compound":"left",# paste"paste_label":"Paste","paste_accelerator":"Ctrl+V","paste_image":tk.PhotoImage(data=ICON_PASTE),"paste_compound":"left",# delete"delete_label":"Delete","delete_accelerator":"Del","delete_image":tk.PhotoImage(data=ICON_CLEAR),"delete_compound":"left",# clear contents"clear_contents_label":"Clear contents","clear_contents_accelerator":"Del","clear_contents_image":tk.PhotoImage(data=ICON_CLEAR),"clear_contents_compound":"left",# del columns"delete_columns_label":"Delete columns","delete_columns_accelerator":"","delete_columns_image":tk.PhotoImage(data=ICON_DEL),"delete_columns_compound":"left",# insert columns left"insert_columns_left_label":"Insert columns left","insert_columns_left_accelerator":"","insert_columns_left_image":tk.PhotoImage(data=ICON_ADD),"insert_columns_left_compound":"left",# insert columns right"insert_columns_right_label":"Insert columns right","insert_columns_right_accelerator":"","insert_columns_right_image":tk.PhotoImage(data=ICON_ADD),"insert_columns_right_compound":"left",# insert single column"insert_column_label":"Insert column","insert_column_accelerator":"","insert_column_image":tk.PhotoImage(data=ICON_ADD),"insert_column_compound":"left",# del rows"delete_rows_label":"Delete rows","delete_rows_accelerator":"","delete_rows_image":tk.PhotoImage(data=ICON_DEL),"delete_rows_compound":"left",# insert rows above"insert_rows_above_label":"Insert rows above","insert_rows_above_accelerator":"","insert_rows_above_image":tk.PhotoImage(data=ICON_ADD),"insert_rows_above_compound":"left",# insert rows below"insert_rows_below_label":"Insert rows below","insert_rows_below_accelerator":"","insert_rows_below_image":tk.PhotoImage(data=ICON_ADD),"insert_rows_below_compound":"left",# insert single row"insert_row_label":"Insert row","insert_row_accelerator":"","insert_row_image":tk.PhotoImage(data=ICON_ADD),"insert_row_compound":"left",# sorting# labels"sort_cells_label":"Sort Asc.","sort_cells_x_label":"Sort row-wise Asc.","sort_row_label":"Sort values Asc.","sort_column_label":"Sort values Asc.","sort_rows_label":"Sort rows Asc.","sort_columns_label":"Sort columns Asc.",# reverse labels"sort_cells_reverse_label":"Sort Desc.","sort_cells_x_reverse_label":"Sort row-wise Desc.","sort_row_reverse_label":"Sort values Desc.","sort_column_reverse_label":"Sort values Desc.","sort_rows_reverse_label":"Sort rows Desc.","sort_columns_reverse_label":"Sort columns Desc.",# accelerators"sort_cells_accelerator":"","sort_cells_x_accelerator":"","sort_row_accelerator":"","sort_column_accelerator":"","sort_rows_accelerator":"","sort_columns_accelerator":"",# reverse accelerators"sort_cells_reverse_accelerator":"","sort_cells_x_reverse_accelerator":"","sort_row_reverse_accelerator":"","sort_column_reverse_accelerator":"","sort_rows_reverse_accelerator":"","sort_columns_reverse_accelerator":"",# images"sort_cells_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_cells_x_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_row_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_column_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_rows_image":tk.PhotoImage(data=ICON_SORT_ASC),"sort_columns_image":tk.PhotoImage(data=ICON_SORT_ASC),# compounds"sort_cells_compound":"left","sort_cells_x_compound":"left","sort_row_compound":"left","sort_column_compound":"left","sort_rows_compound":"left","sort_columns_compound":"left",# reverse images"sort_cells_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_cells_x_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_row_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_column_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_rows_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),"sort_columns_reverse_image":tk.PhotoImage(data=ICON_SORT_DESC),# reverse compounds"sort_cells_reverse_compound":"left","sort_cells_x_reverse_compound":"left","sort_row_reverse_compound":"left","sort_column_reverse_compound":"left","sort_rows_reverse_compound":"left","sort_columns_reverse_compound":"left",# select all"select_all_label":"Select all","select_all_accelerator":"Ctrl+A","select_all_image":tk.PhotoImage(data=ICON_SELECT_ALL),"select_all_compound":"left",# undo"undo_label":"Undo","undo_accelerator":"Ctrl+Z","undo_image":tk.PhotoImage(data=ICON_UNDO),"undo_compound":"left",# redo"redo_label":"Redo","redo_accelerator":"Ctrl+Shift+Z","redo_image":tk.PhotoImage(data=ICON_REDO),"redo_compound":"left",
Example:
# changing the copy label to the spanish for Copysheet.set_options(copy_label="Copiar",copy_image=tk.PhotoImage(file="filepath_to_img.png"),copy_compound="left")
Notes:
- To remove the
Copy plainright click menu option when copy is enabled you can overwrite it, e.g.
fromtksheetimport (ICON_COPY,Sheet,ctrl_key,)# ...self.sheet.set_options(copy_plain_label="Copy",copy_plain_accelerator="Ctrl+C",copy_plain_image=tk.PhotoImage(data=ICON_COPY),copy_plain_compound="left",copy_plain_bindings=[f"<{ctrl_key}-c>",f"<{ctrl_key}-C>", ],)
You can change the bindings for tksheets in-built functionality such as cut, copy, paste by using theset_options() function with any the following keyword arguments:
copy_bindingscut_bindingspaste_bindingsundo_bindingsredo_bindingsdelete_bindingsselect_all_bindingsselect_columns_bindingsselect_rows_bindingsrow_start_bindingstable_start_bindingstab_bindingsup_bindingsright_bindingsdown_bindingsleft_bindingsshift_up_bindingsshift_right_bindingsshift_down_bindingsshift_left_bindingsprior_bindingsnext_bindingsfind_bindingsfind_next_bindingsfind_previous_bindingsescape_bindingstoggle_replace_bindings
The argument must be alist oftkinter bindingstrs. In the below example the binding for copy is changed to"<Control-e>" and"<Control-E>".
# changing the binding for copysheet.set_options(copy_bindings=["<Control-e>","<Control-E>"])
The default values for these bindings can be found in the tksheet filesheet_options.py.
There is limited support in tkinter for keybindings in languages other than english, for example tkinters.bind() function doesn't cooperate with cyrillic characters.
There are ways around this however, see below for a limited example of how this might be achieved:
from __future__importannotationsimporttkinterastkfromtksheetimportSheetclassdemo(tk.Tk):def__init__(self)->None:tk.Tk.__init__(self)self.grid_columnconfigure(0,weight=1)self.grid_rowconfigure(0,weight=1)self.sheet=Sheet(parent=self,data=[[f"{r}{c}"forcinrange(5)]forrinrange(5)], )self.sheet.enable_bindings()self.sheet.grid(row=0,column=0,sticky="nswe")self.bind_all("<Key>",self.any_key)defany_key(self,event:tk.Event)->None:""" Establish that the Control key is held down """ctrl= (event.state&4>0)ifnotctrl:return""" From here you can use event.keycode and event.keysym to determine which key has been pressed along with Control """print(event.keycode)print(event.keysym)""" If the keys are the ones you want to have bound to Sheet functionality You can then call the Sheets functionality using event_generate() For example: """# if the key is correct then:self.sheet.event_generate("<<Copy>>")app=demo()app.mainloop()
Intksheet versions >7 there are functions which utilise an object namedSpan. These objects are a subclass ofdict but with various additions and dot notation attribute access.
Spans basically represent ancontiguous area of the sheet. They can beone of threekinds:
"cell""row""column"
They can be used with some of the sheets functions such as data getting/setting and creation of things on the sheet such as dropdown boxes.
Spans store:
- A reference to the
Sheet()they were created with. - Variables which represent a particular range of cells and properties for accessing these ranges.
- Variables which represent options for those cells.
- Methods which can modify the above variables.
- Methods which can act upon the table using the above variables such as
highlight,format, etc.
Whether cells, rows or columns are affected will depend on the spanskind.
You can create a span by:
- Using the
span()function e.g.sheet.span("A1")represents the cellA1
or
- Using square brackets on a Sheet object e.g.
sheet["A1"]represents the cellA1
Both methods return the created span object.
span(*key:CreateSpanTypes,type_:str="",name:str="",table:bool=True,index:bool=False,header:bool=False,tdisp:bool=False,idisp:bool=True,hdisp:bool=True,transposed:bool=False,ndim:int=0,convert:Callable|None=None,undo:bool=True,emit_event:bool=False,widget:Any=None,expand:None|str=None,formatter_options:dict|None=None,**kwargs,)->Span"""Create a span / get an existing span by nameReturns the created span"""
Parameters:
keyyou do not have to provide an argument forkey, if no argument is provided then the span will be a full sheet span. Otherwisekeycan be the following types which are type hinted asCreateSpanTypes:Nonestre.g.sheet.span("A1:F1")inte.g.sheet.span(0)slicee.g.sheet.span(slice(0, 4))Sequence[int | None, int | None]representing a cell ofrow, columne.g.sheet.span(0, 0)Sequence[Sequence[int | None, int | None], Sequence[int | None, int | None]]representingsheet.span(start row, start column, up to but not including row, up to but not including column)e.g.sheet.span(0, 0, 2, 2)Spane.gsheet.span(another_span)
type_(str) must be either an empty string""or one of the following:"format","highlight","dropdown","checkbox","readonly","align".name(str) used for named spans or for identification. If no name is provided then a name is generated for the span which is based on an internal integer ticker and then converted to a string in the same way column names are.table(bool) whenTruewill make all functions used with the span target the main table as well as the header/index if those areTrue.index(bool) whenTruewill make all functions used with the span target the index as well as the table/header if those areTrue.header(bool) whenTruewill make all functions used with the span target the header as well as the table/index if those areTrue.tdisp(bool) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the table, not underlying cell data.idisp(bool) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the index, not underlying cell data.hdisp(bool) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the header, not underlying cell data.transposed(bool) is used by data getting and setting functions that utilize spans. WhenTrue:- Returned sublists from data getting functions will represent columns rather than rows.
- Data setting functions will assume that a single sequence is a column rather than row and that a list of lists is a list of columns rather than a list of rows.
ndim(int) is used by data getting functions that utilize spans, it must be either0or1or2.0is the default setting which will make the return value vary based on what it is. For example if the gathered data is only a single cell it will return a value instead of a list of lists with a single list containing a single value. A single row will be a single list.1will force the return of a single list as opposed to a list of lists.2will force the return of a list of lists.
convert(None,Callable) can be used to modify the data using a function before returning it. The data sent to theconvertfunction will be as it was before normally returning (afterndimhas potentially modified it).undo(bool) is used by data modifying functions that utilize spans. WhenTrueand if undo is enabled for the sheet then the end user will be able to undo/redo the modification.emit_eventwhenTrueand when using data setting functions that utilize spans causes a"<<SheetModified>>event to occur if it has been bound, seehere for more information on binding this event.widget(Any) is the reference to the original sheet which created the span. This can be changed to a different sheet if required e.g.my_span.widget = new_sheet.expand(None,str) must be eitherNoneor:"table"/"both"expand the span both down and right from the span start to the ends of the table."right"expand the span right to the end of the tablexaxis."down"expand the span downwards to the bottom of the tableyaxis.
formatter_options(dict,None) must be eitherNoneordict. If providing adictit must be the same structure as used in format functions, seehere for more information. Used to turn the span into a format type span which:- When using
get_data()will format the returned data. - When using
set_data()will format the data being set butNOT create a new formatting rule on the sheet.
- When using
**kwargsyou can provide additional keyword arguments to the function for example those used inspan.highlight()orspan.dropdown()which are used when applying a named span to a table.
Notes:
- To create a named span seehere.
When creating a span using the below methods:
strs use excel syntax and the indexing rule of up toAND including.ints use python syntax and the indexing rule of up to butNOT including.
For example python index0 as in[0] is the first whereas excel index1 as in"A1" is the first.
If you need to convert python indexes into column letters you can use the functionnum2alpha importable fromtksheet:
fromtksheetimport (Sheet,num2alphaasn2a,)# column index five as a lettern2a(5)
span=sheet[0,0]# cell A1span=sheet[(0,0)]# cell A1span=sheet["A1:C1"]# cells A1, B1, C1span=sheet[0,0,1,3]# cells A1, B1, C1span=sheet[(0,0,1,3)]# cells A1, B1, C1span=sheet[(0,0), (1,3)]# cells A1, B1, C1span=sheet[((0,0), (1,3))]# cells A1, B1, C1span=sheet["A1:2"]span=sheet[0,0,2,None]"""["A1:2"]All the cells starting from (0, 0)expanding down to include row 1but not including cells beyond row1 and expanding out to include allcolumns A B C D1 x x x x2 x x x x34..."""span=sheet["A1:B"]span=sheet[0,0,None,2]"""["A1:B"]All the cells starting from (0, 0)expanding out to include column 1but not including cells beyond column1 and expanding down to include allrows A B C D1 x x2 x x3 x x4 x x..."""
span=sheet[0]# first rowspan=sheet["1"]# first rowspan=sheet[0:2]# first two rowsspan=sheet["1:2"]# first two rowsspan=sheet[:]# entire sheetspan=sheet[":"]# entire sheetspan=sheet[:2]# first two rowsspan=sheet[":2"]# first two rows""" THESE TWO HAVE DIFFERENT OUTCOMES """span=sheet[2:]# all rows after and not inlcuding python index 1span=sheet["2:"]# all rows after and not including python index 0
span=sheet[None,0,None,1]# first columnspan=sheet["A"]# first columnspan=sheet[None,0,None,2]# only first two columnsspan=sheet["A:B"]# only first two columnsspan=sheet[None,2,None,None]# from the third columnspan=sheet["C:"]# from the third columnspan=sheet[None,0,None,None]# entire sheetspan=sheet["A:"]# entire sheet
Header only span
span=sheet[None,0,None,1].options(table=False,header=True)# first column header only
Index only span
span=sheet[0].options(table=False,index=True)# first row index only
The same arguments as shown forcell,row andcolumn span creation using square brackets can also be used for creating spans using theSheet.span() function. e.g:
span = sheet.span(0, 0) # cell A1span = sheet.span(0) # first rowspan = sheet.span(None, 0, None, 1) # first column
More examples below:
"""EXAMPLES USING span()""""""USING NO ARGUMENTS"""sheet.span()# entire sheet, in this case not including header or index"""USING ONE ARGUMENTstr or int or slice()"""# with one argument you can use the same string syntax used for square bracket span creationsheet.span("A1")sheet.span(0)# row at python index 0, all columnssheet.span(slice(0,2))# rows at python indexes 0 and 1, all columnssheet.span(":")# entire sheet"""USING TWO ARGUMENTSint | None, int | Noneor(int | None, int | None), (int | None, int | None)"""sheet.span(0,0)# row 0, column 0 - the first cellsheet.span(0,None)# row 0, all columnssheet.span(None,0)# column 0, all rowssheet.span((0,0), (1,1))# row 0, column 0 - the first cellsheet.span((0,0), (None,2))# rows 0 - end, columns 0 and 1"""USING FOUR ARGUMENTSint | None, int | None, int | None, int | None"""sheet.span(0,0,1,1)# row 0, column 0 - the first cellsheet.span(0,0,None,2)# rows 0 - end, columns 0 and 1
""" GETTING AN EXISTING NAMED SPAN """# you can retrieve an existing named span quickly by surrounding its name in <> e.g.named_span_retrieval=sheet["<the name of the span goes here>"]
Spans have a few@property functions:
span.kindspan.rowsspan.columnsspan.coords
span.kind
- Returns either
"cell","row"or"column".
span=sheet.span("A1:C4")print (span.kind)# prints "cell"span=sheet.span(":")print (span.kind)# prints "cell"span=sheet.span("1:3")print (span.kind)# prints "row"span=sheet.span("A:C")print (span.kind)# prints "column"# after importing num2alpha from tksheetprint (sheet[num2alpha(0)].kind)# prints "column"
span.rowsspan.columns
Returns aSpanRange object. The below examples are forspan.rows but you can usespan.columns for the spans columns exactly the same way.
# use as an iteratorspan=sheet.span("A1:C4")forrowinspan.rows:pass# use as a reversed iteratorforrowinreversed(span.rows):pass# check row membershipspan=sheet.span("A1:C4")print (2inspan.rows)# prints True# check span.rows equality, also can do not equalspan=self.sheet["A1:C4"]span2=self.sheet["1:4"]print (span.rows==span2.rows)# prints True# check lenspan=self.sheet["A1:C4"]print (len(span.rows))# prints 4
Spans have the following methods, all of which return the span object itself so you can chain the functions e.g.span.options(undo=True).clear().bg = "indianred1"
span.options(type_:str|None=None,name:str|None=None,table:bool|None=None,index:bool|None=None,header:bool|None=None,tdisp:bool|None=None,idisp:bool|None=None,hdisp:bool|None=None,transposed:bool|None=None,ndim:int|None=None,convert:Callable|None=None,undo:bool|None=None,emit_event:bool|None=None,widget:Any=None,expand:str|None=None,formatter_options:dict|None=None,**kwargs,)->Span
Note that ifNone is used for any of the following parameters then thatSpans attribute will be unchanged:
type_(str,None) if notNonethen must be either an empty string""or one of the following:"format","highlight","dropdown","checkbox","readonly","align".name(str,None) is used for named spans or for identification.table(bool,None) whenTruewill make all functions used with the span target the main table as well as the header/index if those areTrue.index(bool,None) whenTruewill make all functions used with the span target the index as well as the table/header if those areTrue.header(bool,None) whenTruewill make all functions used with the span target the header as well as the table/index if those areTrue.tdisp(bool,None) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the table, not underlying cell data.idisp(bool,None) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the index, not underlying cell data.hdisp(bool,None) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the header, not underlying cell data.transposed(bool,None) is used by data getting and setting functions that utilize spans. WhenTrue:- Returned sublists from data getting functions will represent columns rather than rows.
- Data setting functions will assume that a single sequence is a column rather than row and that a list of lists is a list of columns rather than a list of rows.
ndim(int,None) is used by data getting functions that utilize spans, it must be either0or1or2.0is the default setting which will make the return value vary based on what it is. For example if the gathered data is only a single cell it will return a value instead of a list of lists with a single list containing a single value. A single row will be a single list.1will force the return of a single list as opposed to a list of lists.2will force the return of a list of lists.
convert(Callable,None) can be used to modify the data using a function before returning it. The data sent to theconvertfunction will be as it was before normally returning (afterndimhas potentially modified it).undo(bool,None) is used by data modifying functions that utilize spans. WhenTrueand if undo is enabled for the sheet then the end user will be able to undo/redo the modification.emit_event(bool,None) is used by data modifying functions that utilize spans. WhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.widget(Any) is the reference to the original sheet which created the span. This can be changed to a different sheet if required e.g.my_span.widget = new_sheet.expand(str,None) must be eitherNoneor:"table"/"both"expand the span both down and right from the span start to the ends of the table."right"expand the span right to the end of the tablexaxis."down"expand the span downwards to the bottom of the tableyaxis.
formatter_options(dict,None) must be eitherNoneordict. If providing adictit must be the same structure as used in format functions, seehere for more information. Used to turn the span into a format type span which:- When using
get_data()will format the returned data. - When using
set_data()will format the data being set butNOT create a new formatting rule on the sheet.
- When using
**kwargsyou can provide additional keyword arguments to the function for example those used inspan.highlight()orspan.dropdown()which are used when applying a named span to a table.- This function returns the span instance itself (
self).
# entire sheetspan=sheet["A1"].options(expand="both")# column Aspan=sheet["A1"].options(expand="down")# row 0span=sheet["A1"].options(expand="right",ndim=1,# to return a single list when getting data)
All of a spans modifiable attributes are listed here:
from_r(int) represents which row the span starts at, must be a positiveint.from_c(int) represents which column the span starts at, must be a positiveint.upto_r(int,None) represents which row the span ends at, must be a positiveintorNone.Nonemeans always up to and including the last row.upto_c(int,None) represents which column the span ends at, must be a positiveintorNone.Nonemeans always up to and including the last column.type_(str) must be either an empty string""or one of the following:"format","highlight","dropdown","checkbox","readonly","align".name(str) used for named spans or for identification. If no name is provided then a name is generated for the span which is based on an internal integer ticker and then converted to a string in the same way column names are.table(bool) whenTruewill make all functions used with the span target the main table as well as the header/index if those areTrue.index(bool) whenTruewill make all functions used with the span target the index as well as the table/header if those areTrue.header(bool) whenTruewill make all functions used with the span target the header as well as the table/index if those areTrue.tdisp(bool) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the table, not underlying cell data.idisp(bool) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the index, not underlying cell data.hdisp(bool) is used by data getting functions that utilize spans and whenTruethe function retrieves screen displayed data for the header, not underlying cell data.transposed(bool) is used by data getting and setting functions that utilize spans. WhenTrue:- Returned sublists from data getting functions will represent columns rather than rows.
- Data setting functions will assume that a single sequence is a column rather than row and that a list of lists is a list of columns rather than a list of rows.
ndim(int) is used by data getting functions that utilize spans, it must be either0or1or2.0is the default setting which will make the return value vary based on what it is. For example if the gathered data is only a single cell it will return a value instead of a list of lists with a single list containing a single value. A single row will be a single list.1will force the return of a single list as opposed to a list of lists.2will force the return of a list of lists.
convert(None,Callable) can be used to modify the data using a function before returning it. The data sent to theconvertfunction will be as it was before normally returning (afterndimhas potentially modified it).undo(bool) is used by data modifying functions that utilize spans. WhenTrueand if undo is enabled for the sheet then the end user will be able to undo/redo the modification.emit_event(bool) is used by data modifying functions that utilize spans. WhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.widget(Any) is the reference to the original sheet which created the span. This can be changed to a different sheet if required e.g.my_span.widget = new_sheet.kwargsadictcontaining keyword arguments relevant for functions such asspan.highlight()orspan.dropdown()which are used when applying a named span to a table.
If necessary you can also modify these attributes the same way you would an objects. e.g.
# span now takes in all columns, including Aspan=self.sheet("A")span.upto_c=None# span now adds to sheets undo stack when using data modifying functions that use spansspan=self.sheet("A")span.undo=True
Formats table data, see the help onformatting for more information. Note that using this function also creates a format rule for the affected table cells.
span.format(formatter_options:dict= {},formatter_class:Any=None,redraw:bool=True,**kwargs,)->Span
Example:
# using square bracketssheet[:].format(int_formatter())# or instead using sheet.span()sheet.span(":").format(int_formatter())
These examples show the formatting of the entire sheet (not including header and index) asint and creates a format rule for all currently existing cells.Named spans are required to create a rule for all future existing cells as well, for example those created by the end user inserting rows or columns.
Delete any currently existing format rules for parts of the table that are covered by the span. Should not be used where there are data formatting rules created by named spans, seeNamed spans for more information.
span.del_format()->Span
Example:
span1=sheet[2:4]span1.format(float_formatter())span1.del_format()
span.highlight(bg:bool|None|str=False,fg:bool|None|str=False,end:bool|None=None,overwrite:bool=False,redraw:bool=True,)->Span
There are two ways to create highlights using a span:
Method 1 example using.highlight():
# highlights column A background red, text color blacksheet["A"].highlight(bg="red",fg="black")# the same but after having saved a spanmy_span=sheet["A"]my_span.highlight(bg="red",fg="black")
Method 2 example using.bg/.fg:
# highlights column A background red, text color blacksheet["A"].bg="red"sheet["A"].fg="black"# the same but after having saved a spanmy_span=sheet["A"]my_span.bg="red"my_span.fg="black"
Delete any currently existing highlights for parts of the sheet that are covered by the span. Should not be used where there are highlights created by named spans, seeNamed spans for more information.
span.dehighlight()->Span
Example:
span1=sheet[2:4].highlight(bg="red",fg="black")span1.dehighlight()
Creates dropdown boxes for parts of the sheet that are covered by the span. For more information seehere.
span.dropdown(values:list= [],set_value:Any=None,state:Literal["normal","readonly","disabled"]="normal",redraw:bool=True,selection_function:Callable|None=None,modified_function:Callable|None=None,search_function:Callable=dropdown_search_function,validate_input:bool=True,text:None|str=None,)->Span
Example:
sheet["D"].dropdown(values=["on","off"],set_value="off",)
Delete dropdown boxes for parts of the sheet that are covered by the span. Should not be used where there are dropdown box rules created by named spans, seeNamed spans for more information.
span.del_dropdown()->Span
Example:
dropdown_span=sheet["D"].dropdown(values=["on","off"],set_value="off")dropdown_span.del_dropdown()
Create check boxes for parts of the sheet that are covered by the span.
span.checkbox(edit_data:bool=True,checked:bool|None=None,state:Literal["normal","disabled"]="normal",redraw:bool=True,check_function:Callable|None=None,text:str="",)->Span
Parameters:
edit_datawhenTrueedits the underlying cell data to eithercheckedifcheckedis aboolor tries to convert the existing cell data to abool.checkedis the initial creation value to set the box to, ifNonethen andedit_dataisTruethen it will try to convert the underlying cell data to abool.statecan be"normal"or"disabled". If"disabled"then color will be same as table grid lines, else it will be the cells text color.check_functioncan be used to trigger a function when the user clicks a checkbox.textdisplays text next to the checkbox in the cell, but will not be used as data, data will either beTrueorFalse.
Notes:
- To get the current checkbox value either:
- Get the cell data, more informationhere.
- Use the parameter
check_functionwith a function of your own creation to be called when the checkbox is set by the user.
Example:
sheet["D"].checkbox(checked=True,text="Switch",)
Delete check boxes for parts of the sheet that are covered by the span. Should not be used where there are check box rules created by named spans, seeNamed spans for more information.
span.del_checkbox()->Span
Example:
checkbox_span=sheet["D"].checkbox(checked=True,text="Switch")checkbox_span.del_checkbox()
Create a readonly rule for parts of the table that are covered by the span.
span.readonly(readonly:bool=True)->Span
- Using
span.readonly(False)deletes any existing readonly rules for the span. Should not be used where there are readonly rules created by named spans, seeNamed spans for more information.
Create/delete notes for cells, rows or columns for parts of the table that are covered by the span. Seehere for more information on Notes.
span.note(note:str|None=None,readonly:bool=True)->Span
- Using
span.note()orspan.note(None)deletes any existing notes for the span.
Create a text alignment rule for parts of the sheet that are covered by the span.
span.align(align:str|None,redraw:bool=True,)->Span
align(str,None) must be either:None- clears the alignment rule"c","center","centre""w","west","left""e","east","right"
Example:
sheet["D"].align("right")
There are two ways to create alignment rules using a span:
Method 1 example using.align():
# column D right text alignmentsheet["D"].align("right")# the same but after having saved a spanmy_span=sheet["D"]my_span.align("right")
Method 2 example using.align =:
# column D right text alignmentsheet["D"].align="right"# the same but after having saved a spanmy_span=sheet["D"]my_span.align="right"
Delete text alignment rules for parts of the sheet that are covered by the span. Should not be used where there are alignment rules created by named spans, seeNamed spans for more information.
span.del_align()->Span
Example:
align_span=sheet["D"].align("right")align_span.del_align()
Clear cell data from all cells that are covered by the span.
span.clear(undo:bool|None=None,emit_event:bool|None=None,redraw:bool=True,)->Span
Parameters:
undo(bool,None) WhenTrueif undo is enabled for the end user they will be able to undo the clear change.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
Example:
# clears column Dsheet["D"].clear()
Tag cells, rows or columns depending on the spans kind, more information on tagshere.
tag(*tags)->Span
Notes:
- If
span.kindis"cell"then cells will be tagged, if it's a row span then rows will be and so for columns.
Example:
# tags rows 2, 3, 4 with "hello world"sheet[2:5].tag("hello world")
Removeall tags from cells, rows or columns depending on the spans kind, more information on tagshere.
untag()->Span
Notes:
- If
span.kindis"cell"then cells will be untagged, if it's a row span then rows will be and so for columns.
Example:
# tags rows 2, 3, 4 with "hello" and "bye"sheet[2:5].tag("hello","bye")# removes both "hello" and "bye" tags from rows 2, 3, 4sheet[2:5].untag()
The attributespan.transposed (bool) is used by data getting and setting functions that utilize spans. WhenTrue:- Returned sublists from data getting functions will represent columns rather than rows.- Data setting functions will assume that a single sequence is a column rather than row and that a list of lists is a list of columns rather than a list of rows.
You can toggle the transpotition of the span by using:
span.transpose()->Span
If the attribute is alreadyTrue this makes itFalse and vice versa.
span=sheet["A:D"].transpose()# this span is now transposedprint (span.transposed)# prints Truespan.transpose()# this span is no longer transposedprint (span.transposed)# prints False
Expand the spans area either all the way to the right (x axis) or all the way down (y axis) or both.
span.expand(direction:str="both")->Span
direction(None,str) must be eitherNoneor:"table"/"both"expand the span both down and right from the span start to the ends of the table."right"expand the span right to the end of the table x axis."down"expand the span downwards to the bottom of the table y axis.
Named spans are like spans but with a type, some keyword arguments saved inspan.kwargs and then created by using aSheet() function. Like spans, named spans are alsocontiguous areas of the sheet.
Named spans can be used to:
- Create options (rules) for the sheet which will expand/contract when new cells are added/removed. For example if a user were to insert rows in the middle of some already highlighted rows:
- With ordinary row highlights the newly inserted rows wouldNOT be highlighted.
- With named span row highlights the newly inserted rows would also be highlighted.
- Quickly delete an existing option from the table whereas an ordinary span would not keep track of where the options have been moved.
Note that generally when a user moves rows/columns around the dimensions of the named span essentially move with either end of the span:
- The new start of the span will be wherever the start row/column moves.
- The new end of the span will be wherever the end row/column moves.The exceptions to this rule are when a span is expanded or has been created with
Nones or the start of0and no end or end ofNone.
For the end user, when a span is just a single row/column (and is not expanded/unlimited) it cannot be expanded but it can be deleted if the row/column is deleted.
For a span to become a named span it needs:
- One of the following
type_s:"format","highlight","dropdown","checkbox","readonly","align". - Relevant keyword arguments e.g. if the
type_is"highlight"then arguments forsheet.highlight()foundhere.
After a span has the above items the following function has to be used to make it a named span and create the options on the sheet:
named_span(span:Span)"""Adds a named span to the sheetReturns the span"""
spanmust be an existing span with:- a
name(anameis automatically generated upon span creation if one is not provided). - a
type_as described above. - keyword arguments as described above.
- a
Examples of creating named spans:
# Will highlight rows 3 up to and including 5span1=self.sheet.span("3:5",type_="highlight",bg="green",fg="black",)self.sheet.named_span(span1)# Will always keep the entire sheet formatted as `int` no matter how many rows/columns are insertedspan2=self.sheet.span(":",# you don't have to provide a `type_` when using the `formatter_kwargs` argumentformatter_options=int_formatter(),)self.sheet.named_span(span2)
del_named_span(name:str)
Example, creating and deleting a span:
# span covers the entire sheetself.sheet.named_span(self.sheet.span(name="my highlight span",type_="highlight",bg="dark green",fg="#FFFFFF", ))self.sheet.del_named_span("my highlight span")# ValueError is raised if name does not existself.sheet.del_named_span("this name doesnt exist")# ValueError: Span 'this name doesnt exist' does not exist.
Sets theSheets internal dict of named spans:
set_named_spans(named_spans:None|dict=None)->Sheet
- Using
Nonedeletes all existing named spans
Get an existing named span:
get_named_span(name:str)->dict
Get all existing named spans:
get_named_spans()->dict
ASpan object (more informationhere) is returned when using square brackets on aSheet like so:
span=self.sheet["A1"]
You can also usesheet.span():
span=self.sheet.span("A1")
The above spans represent the cellA1 - row 0, column 0.
A reserved span attribute nameddata can then be used to retrieve the data for cellA1, example below:
span=self.sheet["A1"]cell_a1_data=span.data
The data that is retrieved entirely depends on the area the span represents. You can also usespan.value to the same effect.
There are certain other span attributes which have an impact on the data returned, explained below:
table(bool) whenTruewill make all functions used with the span target the main table as well as the header/index if those areTrue.index(bool) whenTruewill make all functions used with the span target the index as well as the table/header if those areTrue.header(bool) whenTruewill make all functions used with the span target the header as well as the table/index if those areTrue.tdisp(bool) whenTruethe function retrieves screen displayed data for the table, not underlying cell data.idisp(bool) whenTruethe function retrieves screen displayed data for the index, not underlying cell data.hdisp(bool) whenTruethe function retrieves screen displayed data for the header, not underlying cell data.transposed(bool) is used by data getting and setting functions that utilize spans. WhenTrue:- Returned sublists fromdata getting functions will represent columns rather than rows.
- Data setting functions will assume that a single sequence is a column rather than row and that a list of lists is a list of columns rather than a list of rows.
ndim(int) is used by data getting functions that utilize spans, it must be either0or1or2.0is the default setting which will make the return value vary based on what it is. For example if the gathered data is only a single cell it will return a value instead of a list of lists with a single list containing a single value. A single row will be a single list.1will force the return of a single list as opposed to a list of lists.2will force the return of a list of lists.
convert(None,Callable) can be used to modify the data using a function before returning it. The data sent to theconvertfunction will be as it was before normally returning (afterndimhas potentially modified it).widget(Any) is the reference to the original sheet which created the span (this is the widget that data is retrieved from). This can be changed to a different sheet if required e.g.my_span.widget = new_sheet.
Some more complex examples of data retrieval:
"single cell"cell_a1_data=self.sheet["A1"].data"entire sheet including headers and index"entire_sheet_data=self.sheet["A1"].expand().options(header=True,index=True).data"header data, no table or index data"# a list of displayed header cellsheader_data=self.sheet["A:C"].options(table=False,header=True).data# a header valueheader_data=self.sheet["A"].options(table=False,hdisp=False,header=True).data"index data, no table or header data"# a list of displayed index cellsindex_data=self.sheet[:3].options(table=False,index=True).data# or using sheet.span() a list of displayed index cellsindex_data=self.sheet.span(slice(None,3),table=False,index=True).data# a row index valueindex_data=self.sheet[3].options(table=False,idisp=False,index=True).data"sheet data as columns instead of rows, with actual header data"sheet_data=self.sheet[:].transpose().options(hdisp=False,header=True).data# or instead using sheet.span() with only kwargssheet_data=self.sheet.span(transposed=True,hdisp=False,header=True).data
There is also aSheet() function for data retrieval (it is used internally by the above data getting methods):
sheet.get_data(*key:CreateSpanTypes,)->Any
Examples:
data=self.sheet.get_data("A1")data=self.sheet.get_data(0,0,3,3)data=self.sheet.get_data(self.sheet.span(":D",transposed=True))
This is a higher performance method to get a single cells data which may be useful for example when performing a very large number of single cell data retrievals in a loop.
get_cell_data(r:int,c:int,get_displayed:bool=False)->Any
get_displayed(bool) whenTrueretrieves the value that is displayed to the user in the sheet, not the underlying data.
This function is useful if you need a lot of sheet data, and produces one row at a time (may save memory use in certain scenarios). It does not use spans.
yield_sheet_rows(get_displayed:bool=False,get_header:bool=False,get_index:bool=False,get_index_displayed:bool=True,get_header_displayed:bool=True,only_rows:int|Iterator[int]|None=None,only_columns:int|Iterator[int]|None=None,)->Iterator[list[Any]]
Parameters:
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 ofintrow indexes in any order to be the only rows that are returned.only_columns(None,iterable) with this argument you can supply an iterable ofintcolumn indexes in any order to be the only columns that are returned.
@propertydata()
- e.g.
self.sheet.data - Doesn't include header or index 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]but only do so if you know what you're doing.
Sheet objects also have some functions similar to lists.Note that these functions donot include the header or index.
Iterate over table rows:
forrowinself.sheet:print (row)# and in reverseforrowinreversed(self.sheet):print (row)
Check if the table has a particular value (membership):
# returns True or Falsesearch_value="the cell value I'm looking for"print (search_valueinself.sheet)
- Can also check if a row is in the sheet if a
listis used.
get_total_rows(include_index:bool=False)->int
get_total_columns(include_header:bool=False)->int
get_value_for_empty_cell(r:int,c:int,r_ops:bool=True,c_ops:bool=True,)->Any
r_ops/c_opswhen both areTrueit will take into account whatever cell/row/column options exist. When justr_opsisTrueit will take into account row options only and when justc_opsisTrueit will take into account column options only.
Fundamentally, there are two ways to set table data:
- Overwriting the entire table and setting the table data to a new object.
- Modifying the existing data.
set_sheet_data(data:list|tuple|None=None,reset_col_positions:bool=True,reset_row_positions:bool=True,redraw:bool=True,verify:bool=False,reset_highlights:bool=False,keep_formatting:bool=True,delete_options:bool=False,)->Any
Parameters:
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.keep_formatting(bool) whenTruere-applies any prior formatting rules to the new data, ifFalseall prior formatting rules are deleted.delete_options(bool) whenTrueall table options such as dropdowns, check boxes, formatting, highlighting etc. are deleted.
Notes:
- This function does not impact the sheet header or index.
@data.setterdata(value:Any)
Notes:
- Acts like setting an attribute e.g.
sheet.data = [[1, 2, 3], [4, 5, 6]] - Uses the
set_sheet_data()function and its default arguments.
reset(table:bool=True,header:bool=True,index:bool=True,row_heights:bool=True,column_widths:bool=True,cell_options:bool=True,undo_stack:bool=True,selections:bool=True,sheet_options:bool=False,redraw:bool=True,)->Sheet
Parameters:
tablewhenTrueresets the table to an empty list.headerwhenTrueresets the header to an empty list.indexwhenTrueresets the row index to an empty list.row_heightswhenTruedeletes all displayed row lines.column_widthswhenTruedeletes all displayed column lines.cell_optionswhenTruedeletes all dropdowns, checkboxes, highlights, data formatting, etc.undo_stackwhenTrueresets the sheets undo stack to empty.selectionswhenTruedeletes all selection boxes.sheet_optionswhenTrueresets all the sheets options such as colors, font, popup menu labels and many more to default, for a full list of what's reset see the filesheet_options.py.
Notes:
- This function could be useful when a whole new sheet needs to be loaded.
ASpan object (more informationhere) is returned when using square brackets on aSheet like so:
span=self.sheet["A1"]
You can also usesheet.span():
span=self.sheet.span("A1")
The above span example represents the cellA1 - row 0, column 0. A reserved span attribute nameddata (you can also use.value) can then be used to modify sheet datastarting from cellA1. example below:
span=self.sheet["A1"]span.data="new value for cell A1"# or even shorter:self.sheet["A1"].data="new value for cell A1"# or with sheet.span()self.sheet.span("A1").data="new value for cell A1"
If you provide a list or tuple it will set more than one cell, starting from the spans start cell. In the example below three cells are set in the first row,starting from cell B1:
self.sheet["B1"].data= ["row 0, column 1 new value (B1)","row 0, column 2 new value (C1)","row 0, column 3 new value (D1)"]
You can set data in column orientation with a transposed span:
self.sheet["B1"].transpose().data= ["row 0, column 1 new value (B1)","row 1, column 1 new value (B2)","row 2, column 1 new value (B3)"]
When setting data only a spans start cell is taken into account, the end cell is ignored. The example below demonstrates this, the spans end -"B1" is ignored and 4 cells get new values:
self.sheet["A1:B1"].data= ["A1 new val","B1 new val","C1 new val","D1 new val"]
These are the span attributes which have an impact on the data set:
table(bool) whenTruewill make all functions used with the span target the main table as well as the header/index if those areTrue.index(bool) whenTruewill make all functions used with the span target the index as well as the table/header if those areTrue.header(bool) whenTruewill make all functions used with the span target the header as well as the table/index if those areTrue.transposed(bool) is used by data getting and setting functions that utilize spans. WhenTrue:- Returned sublists from data getting functions will represent columns rather than rows.
- Data setting functions will assume that a single sequence is a column rather than row and that a list of lists is a list of columns rather than a list of rows.
widget(Any) is the reference to the original sheet which created the span (this is the widget that data is set to). This can be changed to a different sheet if required e.g.my_span.widget = new_sheet.
Some more complex examples of setting data:
"""SETTING ROW DATA"""# first row gets some new values and the index gets a new value alsoself.sheet[0].options(index=True).data= ["index val","row 0 col 0","row 0 col 1","row 0 col 2"]# or instead using sheet.span() first row gets some new values and the index gets a new value alsoself.sheet.span(0,index=True).data= ["index val","row 0 col 0","row 0 col 1","row 0 col 2"]# first two rows get some new values, index includedself.sheet[0].options(index=True).data= [["index 0","row 0 col 0","row 0 col 1","row 0 col 2"], ["index 1","row 1 col 0","row 1 col 1","row 1 col 2"]]"""SETTING COLUMN DATA"""# first column gets some new values and the header gets a new value alsoself.sheet["A"].options(transposed=True,header=True).data= ["header val","row 0 col 0","row 1 col 0","row 2 col 0"]# or instead using sheet.span() first column gets some new values and the header gets a new value alsoself.sheet.span("A",transposed=True,header=True).data= ["header val","row 0 col 0","row 1 col 0","row 2 col 0"]# first two columns get some new values, header includedself.sheet["A"].options(transposed=True,header=True).data= [["header 0","row 0 col 0","row 1 col 0","row 2 col 0"], ["header 1","row 0 col 1","row 1 col 1","row 2 col 1"]]"""SETTING CELL AREA DATA"""# cells B2, C2, B3, C3 get new valuesself.sheet["B2"].data= [["B2 new val","C2 new val"], ["B3 new val","C3 new val"]]# or instead using sheet.span() cells B2, C2, B3, C3 get new valuesself.sheet.span("B2").data= [["B2 new val","C2 new val"], ["B3 new val","C3 new val"]]"""SETTING CELL AREA DATA INCLUDING HEADER AND INDEX"""self.sheet_span=self.sheet.span(header=True,index=True,hdisp=False,idisp=False,)# set data for the span which was created aboveself.sheet_span.data= [["","A","B","C"] ["1","A1","B1","C1"], ["2","A2","B2","C2"]]
# clears both undos and redosreset_undos()->Sheet# get the Sheets modifiable deque variables which store changes for undo and redoget_undo_stack()->dequeget_redo_stack()->deque# set the Sheets undo and redo stacks, returns Sheet widgetset_undo_stack(stack:deque)->Sheetset_redo_stack(stack:deque)->Sheet
You can also use theSheet functionset_data().
set_data(*key:CreateSpanTypes,data:Any=None,undo:bool|None=None,emit_event:bool|None=None,redraw:bool=True,event_data:EventDataDict|None=None,)->EventDataDict
Parameters:
undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
Example:
self.sheet.set_data("A1", [["","A","B","C"] ["1","A1","B1","C1"], ["2","A2","B2","C2"]],)
You can clear cells/rows/columns using aspansclear() function or the Sheetsclear() function. Below is the Sheets clear function:
clear(*key:CreateSpanTypes,undo:bool|None=None,emit_event:bool|None=None,redraw:bool=True,)->EventDataDict
undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
insert_row(row:list[Any]|tuple[Any]|None=None,idx:str|int|None=None,height:int|None=None,row_index:bool=False,fill:bool=True,undo:bool=True,emit_event:bool=False,redraw:bool=True,)->EventDataDict
Parameters:
- Leaving
rowasNoneinserts 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.row_indexwhenTrueassumes there is a row index value at the start of the row.fillwhenTrueany provided rows that are shorter than the Sheets longest row will be filled with empty values up to the length of the longest row.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
insert_column(column:list[Any]|tuple[Any]|None=None,idx:str|int|None=None,width:int|None=None,header:bool=False,fill:bool=True,undo:bool=True,emit_event:bool=False,redraw:bool=True,)->EventDataDict
Parameters:
- Leaving
columnasNoneinserts an empty column, e.g.insert_column()will append an empty column to the sheet. widthis the new columns displayed width in pixels, leave asNonefor default.headerwhenTrueassumes there is a header value at the start of the column.fillwhenTrueany provided columns that are shorter than the Sheets longest column will be filled with empty values up to the length of the longest column.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
insert_columns(columns:list[tuple[Any]|list[Any]]|tuple[tuple[Any]|list[Any]]|int=1,idx:str|int|None=None,widths:list[int]|tuple[int]|None=None,headers:bool=False,fill:bool=True,undo:bool=True,emit_event:bool=False,create_selections:bool=True,add_row_heights:bool=True,push_ops:bool=True,redraw:bool=True,)->EventDataDict
Parameters:
columnsifintwill insert that number of blank columns.idx(str,int,None) eitherstre.g."A"for0,intorNonefor end.widthsare the new columns displayed widths in pixels, leave asNonefor default.headerswhenTrueassumes there are headers values at the start of each column.fillwhenTrueany provided columns that are shorter than the Sheets longest column will be filled with empty values up to the length of the longest column.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.create_selectionswhenTruecreates a selection box for the newly inserted columns.add_row_heightswhenTruecreates rows if there are no pre-existing rows.push_opswhenTrueincreases the indexes of all cell/column options such as dropdown boxes, highlights and data formatting.
insert_rows(rows:list[tuple[Any]|list[Any]]|tuple[tuple[Any]|list[Any]]|int=1,idx:str|int|None=None,heights:list[int]|tuple[int]|None=None,row_index:bool=False,fill:bool=True,undo:bool=True,emit_event:bool=False,create_selections:bool=True,add_column_widths:bool=True,push_ops:bool=True,tree:bool=True,redraw:bool=True,)->EventDataDict
Parameters:
rowsifintwill insert that number of blank rows.idx(str,int,None) eitherstre.g."A"for0,intorNonefor end.heightsare the new rows displayed heights in pixels, leave asNonefor default.row_indexwhenTrueassumes there are row index values at the start of each row.fillwhenTrueany provided rows that are shorter than the Sheets longest row will be filled with empty values up to the length of the longest row.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.create_selectionswhenTruecreates a selection box for the newly inserted rows.add_column_widthswhenTruecreates columns if there are no pre-existing columns.push_opswhenTrueincreases the indexes of all cell/row options such as dropdown boxes, highlights and data formatting.treeis mainly used internally but whenTrueand also when treeview mode is enabled it performs the necessary actions to create new ids and add them to the tree.
del_row(idx:int=0,data_indexes:bool=True,undo:bool=True,emit_event:bool=False,redraw:bool=True,)->EventDataDict
Parameters:
idxis the row to delete.data_indexesonly applicable when there are hidden rows. WhenFalseit makes theidxrepresent a displayed row and not the underlying Sheet data row. WhenTruethe index represent a data index.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
del_rows(rows:int|Iterator[int],data_indexes:bool=True,undo:bool=True,emit_event:bool=False,redraw:bool=True,)->EventDataDict
Parameters:
rowscan be eitherintor an iterable ofints representing row indexes.data_indexesonly applicable when there are hidden rows. WhenFalseit makes therowsindexes represent displayed rows and not the underlying Sheet data rows. WhenTruethe indexes represent data indexes.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
del_column(idx:int=0,data_indexes:bool=True,undo:bool=True,emit_event:bool=False,redraw:bool=True,)->EventDataDict
Parameters:
idxis the column to delete.data_indexesonly applicable when there are hidden columns. WhenFalseit makes theidxrepresent a displayed column and not the underlying Sheet data column. WhenTruethe index represent a data index.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
del_columns(columns:int|Iterator[int],data_indexes:bool=True,undo:bool=True,emit_event:bool=False,redraw:bool=True,)->EventDataDict
Parameters:
columnscan be eitherintor an iterable ofints representing column indexes.data_indexesonly applicable when there are hidden columns. WhenFalseit makes thecolumnsindexes represent displayed columns and not the underlying Sheet data columns. WhenTruethe indexes represent data indexes.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
Expands or contracts the sheetdata dimensions.
sheet_data_dimensions(total_rows:int|None=None,total_columns:int|None=None,)->Sheet
Parameters:
total_rowssets the Sheets number of data rows.total_columnssets the Sheets number of data columns.
set_sheet_data_and_display_dimensions(total_rows:int|None=None,total_columns:int|None=None,)->Sheet
Parameters:
total_rowswhenintwill set the number of the Sheets data and display rows by deleting or adding rows.total_columnswhenintwill set the number of the Sheets data and display columns by deleting or adding columns.
total_rows(number:int|None=None,mod_positions:bool=True,mod_data:bool=True,)->int|Sheet
Parameters:
numbersets the Sheets number of data rows. WhenNonefunction will return the Sheets number of data rows including the number of rows in the index.mod_positionswhenTruealso sets the number of displayed rows.mod_datawhenTruealso sets the number of data rows.
total_columns(number:int|None=None,mod_positions:bool=True,mod_data:bool=True,)->int|Sheet
Parameters:
numbersets the Sheets number of data columns. WhenNonefunction will return the Sheets number of data columns including the number of columns in the header.mod_positionswhenTruealso sets the number of displayed columns.mod_datawhenTruealso sets the number of data columns.
move_row(row:int,moveto:int,)->tuple[dict,dict,dict]
- Note that
rowandmovetoindexes represent displayed indexes and not data. When there are hidden rows this is an important distinction, otherwise it is not at all important. To specifically use data indexes use the functionmove_rows().
move_column(column:int,moveto:int,)->tuple[dict[int,int],dict[int,int],EventDataDict]:
- Note that
columnandmovetoindexes represent displayed indexes and not data. When there are hidden columns this is an important distinction, otherwise it is not at all important. To specifically use data indexes use the functionmove_columns().
move_rows(move_to:int|None=None,to_move:list[int]|None=None,move_data:bool=True,data_indexes:bool=False,create_selections:bool=True,undo:bool=True,emit_event:bool=False,move_heights:bool=True,event_data:EventDataDict|None=None,redraw:bool=True,)->tuple[dict[int,int],dict[int,int],EventDataDict]:
Parameters:
move_tois the new start index for the rows to be moved to.to_moveis alistof row indexes to move to that new position, they will appear in the same order provided.move_datawhenTruemoves not just the displayed row positions but the Sheet data as well.data_indexesis only applicable when there are hidden rows. WhenFalseit makes themove_toandto_moveindexes represent displayed rows and not the underlying Sheet data rows. WhenTruethe indexes represent data indexes.create_selectionscreates new selection boxes based on where the rows have moved.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.move_heightswhenTruealso moves the displayed row lines.
Notes:
- The rows in
to_movedonot have to be contiguous.
move_columns(move_to:int|None=None,to_move:list[int]|None=None,move_data:bool=True,data_indexes:bool=False,create_selections:bool=True,undo:bool=True,emit_event:bool=False,move_widths:bool=True,event_data:EventDataDict|None=None,redraw:bool=True,)->tuple[dict[int,int],dict[int,int],EventDataDict]:
Parameters:
move_tois the new start index for the columns to be moved to.to_moveis alistof column indexes to move to that new position, they will appear in the same order provided.move_datawhenTruemoves not just the displayed column positions but the Sheet data as well.data_indexesis only applicable when there are hidden columns. WhenFalseit makes themove_toandto_moveindexes represent displayed columns and not the underlying Sheet data columns. WhenTruethe indexes represent data indexes.create_selectionscreates new selection boxes based on where the columns have moved.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.move_widthswhenTruealso moves the displayed column lines.
Notes:
- The columns in
to_movedonot have to be contiguous.
mapping_move_columns(data_new_idxs:dict[int,int],disp_new_idxs:None|dict[int,int]=None,move_data:bool=True,create_selections:bool=True,undo:bool=True,emit_event:bool=False,redraw:bool=True,)->tuple[dict[int,int],dict[int,int],EventDataDict]
Parameters:
data_new_idxs(dict[int, int]) must be adictwhere the keys are the data columns to move asints and the values are their new locations asints.disp_new_idxs(None | dict[int, int]) eitherNoneor adictwhere the keys are the displayed columns (basically the column widths) to move asints and the values are their new locations asints. IfNonethen no column widths will be moved.move_datawhenTruemoves not just the displayed column positions but the Sheet data as well.create_selectionscreates new selection boxes based on where the columns have moved.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
Get a mapping (dict) of allold: new column indexes.
full_move_columns_idxs(data_idxs:dict[int,int])->dict[int,int]
- e.g. converts
{0: 1}to{0: 1, 1: 0}if the maximum Sheet column number is1.
mapping_move_rows(data_new_idxs:dict[int,int],disp_new_idxs:None|dict[int,int]=None,move_data:bool=True,create_selections:bool=True,undo:bool=True,emit_event:bool=False,redraw:bool=True,)->tuple[dict[int,int],dict[int,int],EventDataDict]
Parameters:
data_new_idxs(dict[int, int]) must be adictwhere the keys are the data rows to move asints and the values are their new locations asints.disp_new_idxs(None | dict[int, int]) eitherNoneor adictwhere the keys are the displayed rows (basically the row heights) to move asints and the values are their new locations asints. IfNonethen no row heights will be moved.move_datawhenTruemoves not just the displayed row positions but the Sheet data as well.create_selectionscreates new selection boxes based on where the rows have moved.undowhenTrueadds the change to the Sheets undo stack.emit_eventwhenTruecauses a"<<SheetModified>>event to occur if it has been bound, seehere for more information.
Get a mapping (dict) of allold: new row indexes.
full_move_rows_idxs(data_idxs:dict[int,int])->dict[int,int]
- e.g. converts
{0: 1}to{0: 1, 1: 0}if the maximum Sheet row number is1.
equalize_data_row_lengths(include_header:bool=True)->int
- 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.
- Returns the new row length for all rows in the Sheet.
tksheet has various built-in sorting keys and functions which can handle most python objects. Rows can be sorted by a particular column, columns can be sorted by a particular row and a selection of cell's values can be sorted row/column wise.
Note that the readonly functions can be used to disallow sorting of particular cell's/row's/column's values.
There are three built-in sorting keys to choose from but you can always create your own and use that instead. This would enable a custom sorting order of object types. Seehere for more information on how to set the default sorting key.
This is thedefault sorting key for natural sorting of various Python types:
- Won't sort string version numbers.
- Will convert strings to floats.
- Will sort strings that are file paths.
Order:
- None
- Empty strings
- bool
- int, float (inc. strings that are numbers)
- datetime (inc. strings that are dates)
- strings (including string file paths and paths as POSIX strings) & unknown objects withstr
- unknown objects
An alternative sorting key that respects and sorts most version numbers:
- Won't convert strings to floats.
- Will sort string version numbers.
- Will sort strings that are file paths.
- None
- Empty strings
- bool
- int, float
- datetime (inc. strings that are dates)
- strings (including string file paths and paths as POSIX strings) & unknown objects withstr
- unknown objects
A faster key for natural sorting of various Python types. This key should probably be used if you intend on sorting sheets with over a million cells:
- Won't sort strings that are dates very well.
- Won't convert strings to floats.
- Won't sort string file paths very well.
- Will do ok with string version numbers.
- None
- Empty strings
- bool
- int, float
- datetime
- strings (including paths as POSIX strings) & unknown objects withstr
- unknown objects
Setting the sorting key at initialization:
fromtksheetimportSheet,natural_sort_keymy_sheet=Sheet(parent=parent,sort_key=natural_sort_key)
Setting the sorting key after initialization:
fromtksheetimportSheet,natural_sort_keymy_sheet.set_options(sort_key=natural_sort_key)
Using a sorting key with a tksheet sort function call:
fromtksheetimportSheet,natural_sort_keymy_sheet.sort_columns(0,key=natural_sort_key)
- Setting the key like this will, for this call, override whatever key was set at initialization or using
set_options().
sort(*box:CreateSpanTypes,reverse:bool=False,row_wise:bool=False,validation:bool=True,key:Callable|None=None,undo:bool=True,)->EventDataDict
Parameters:
boxes(CreateSpanTypes).reverse(bool) ifTruesorts in reverse (descending) order.row-wise(bool) ifTruesorts values row-wise. Default is column-wise.key(Callable,None) ifNonethen uses the default sorting key.undo(bool) ifTruethen adds the change (if a change was made) to the undo stack.
Notes:
- Sort the values of the box columns, or the values of the box rows if
row_wiseisTrue. - Will not shift cell options (properties) around, only cell values.
- The event name in
EventDataDictfor sorting table values is"edit_table". - The readonly functions can be used to disallow sorting of particular cells values.
Example:
# a box of cells row-wise# start at row 0 & col 0, up to but not including row 10 & col 10my_sheet.sort(0,0,10,10,row_wise=True)# sort the whole tablemy_sheet.sort(None)
defsort_rows(rows:AnyIter[int]|Span|int|None=None,reverse:bool=False,validation:bool=True,key:Callable|None=None,undo:bool=True,)->EventDataDict
Parameters:
rows(AnyIter[int],Span,int,None) the rows to sort.reverse(bool) ifTruethen sorts in reverse (descending) order.key(Callable,None) ifNonethen uses the default sorting key.undo(bool) ifTruethen adds the change (if a change was made) to the undo stack.
Notes:
- Sorts the values of each row independently.
- Will not shift cell options (properties) around, only cell values.
- The event name in
EventDataDictfor sorting table values is"edit_table". - The readonly functions can be used to disallow sorting of particular rows values.
defsort_columns(columns:AnyIter[int]|Span|int|None=None,reverse:bool=False,validation:bool=True,key:Callable|None=None,undo:bool=True,)->EventDataDict
Parameters:
columns(AnyIter[int],Span,int,None) the columns to sort.reverse(bool) ifTruethen sorts in reverse (descending) order.key(Callable,None) ifNonethen uses the default sorting key.undo(bool) ifTruethen adds the change (if a change was made) to the undo stack.
Notes:
- Sorts the values of each column independently.
- Will not shift cell options (properties) around, only cell values.
- The event name in
EventDataDictfor sorting table values is"edit_table". - The readonly functions can be used to disallow sorting of particular columns values.
defsort_rows_by_column(column:int|None=None,reverse:bool=False,key:Callable|None=None,undo:bool=True,)->EventDataDict
Parameters:
column(int,None) ifNonethen it uses the currently selected column to sort.reverse(bool) ifTruethen sorts in reverse (descending) order.key(Callable,None) ifNonethen uses the default sorting key.undo(bool) ifTruethen adds the change (if a change was made) to the undo stack.
Notes:
- Sorts the tree if treeview mode is active.
defsort_columns_by_row(row:int|None=None,reverse:bool=False,key:Callable|None=None,undo:bool=True,)->EventDataDict
Parameters:
row(int,None) ifNonethen it uses the currently selected row to sort.reverse(bool) ifTruethen sorts in reverse (descending) order.key(Callable,None) ifNonethen uses the default sorting key.undo(bool) ifTruethen adds the change (if a change was made) to the undo stack.
An in-built find and replace window can be enabled usingenable_bindings(), e.g:
my_sheet.enable_bindings("find","replace")# all bindings, including find and replacemy_sheet.enable_bindings()
Seeenable_bindings for more information.
There are also someSheet() functions that can be utilized, shown below.
@propertyfind_open()->bool
e.g.find_is_open = sheet.find_open
open_find(focus:bool=False)->Sheet
close_find()->Sheet
next_match(within:bool|None=None,find:str|None=None)->Sheet
prev_match(within:bool|None=None,find:str|None=None)->Sheet
Parameters:
within(bool,None) ifboolthen will override the find windows within selection setting. IfNonethen it will use the find windows setting.find(str,None) ifstrthen will override the find windows search value. IfNonethen it will use the find windows search value.
Notes:
- If looking within selection then hidden rows and columns will be skipped.
replace_all(mapping:dict[str,str],within:bool=False)->EventDataDict
Parameters:
mapping(dict[str, str]) adictof keys to search for and values to replace them with.within(bool) whenTruewill only do replaces inside existing selection boxes.
Notes:
- Will do partial cell data replaces also.
- If looking within selection then hidden rows and columns will be skipped.
When using either notes or tooltips a popup can be made to appear for associated cells when the mouse cursor remains still over a cell.
Tooltips and notes are two different things but both produce the same popup, if using both cell notes and tooltips then the popup with have clickable tabs.
Cell tooltips show the cell's value, they are:
- Disabled by default.
- A global setting and not for individual cells like
notes are. - Editable if the cell itself is editable - if the cell is readonly then the
Celltooltip should be also. - Saved when the mouse leaves the tooltip popup.
You can:
- Change the width and height of tooltip & note popups using the settings:
set_options(tooltip_width=my_width)(int).set_options(tooltip_height=my_height)(int).
- Change the time required for the mouse cursor to stay still before a tooltip appears:
set_options(tooltip_hover_delay=my_delay_in_ms)(int).
Activate & deactivate tooltips either at yourSheets initialization:
sheet=Sheet(parent,tooltips=True)
Or usingset_options()
sheet.set_options(tooltips=True)# or False to deactivate
If you only need tooltips for certain cells and do not want a global setting for all cells then it might be best to use cell notes and leave tooltips disabled (tooltips=False - this is the default setting anyway). More information on notes below.
Notes can be attached to individual cells, rows and columns.
- There is a setting that can be enabled to show a small triangle in the top right hand corner of cells that have notes
note_corners=True. It is disabled by default. - Like other cell properties the priority is 1st cell 2nd row 3rd column.
- Change the width and height of tooltip & note popups using the settings:
set_options(tooltip_width=my_width)(int).set_options(tooltip_height=my_height)(int).
- Retrieve cell notes using the
Sheet.props()function.
Span objects (more informationhere) can be used to create notes for cells, rows, columns, the entire sheet, headers and the index.
You can use either of the following methods:
- Using a span method e.g.
span.note()more informationhere. - Using a sheet method e.g.
sheet.note(Span)
Or if you need user inserted row/columns in the middle of areas with notes to also have notes you can use named spans, more informationhere.
Whether cells, rows or columns have notes depends on thekind of span.
note(*key:CreateSpanTypes,note:str|None=None,readonly:bool=True)->Span
- To delete notes use
Noneas the argument for thenoteparameter. - Use
readonlyFalseto allow the user to edit the existing notes. readonlyisTrueby default.
You can also allow the user to create new notes and delete notes using the settinguser_can_create_notes e.g.sheet.set_options(user_can_create_notes=True). This allows the user to create and modify notes. This also allows note editing even in cells that have been madereadonly in the non-note sense.
If an existing note was created using thenote() function orSpan.note() function andreadonly was set toTrue then the user will not be able to edit or delete that note even ifuser_can_create_notes isTrue.
Examples:
Note for header cell in columnA/0:
self.sheet.span(None,0,None,1).options(table=False,header=True).note("This is column A, what it contains is important!" )
Note for cellA1/(0, 0):
sheet.note(0,0,note="This is cell A1, the first cell.")
Span objects (more informationhere) can be used to highlight cells, rows, columns, the entire sheet, headers and the index.
You can use either of the following methods:
- Using a span method e.g.
span.highlight()more informationhere. - Using a sheet method e.g.
sheet.highlight(Span)
Or if you need user inserted row/columns in the middle of highlight areas to also be highlighted you can use named spans, more informationhere.
Whether cells, rows or columns are highlighted depends on thekind of span.
highlight(*key:CreateSpanTypes,bg:bool|None|str=False,fg:bool|None|str=False,end:bool|None=None,overwrite:bool=False,redraw:bool=True,)->Span
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.bgandfgarguments use either a tkinter color or a hexstrcolor.end(bool) is used for row highlighting whereTruemakes the highlight go to the end of the Sheet window on the x axis.overwrite(bool) whenTrueoverwrites the any previous highlight for that cell/row/column, whereasFalsewill only impact the keyword arguments used.- Highlighting cells, rows or columns will also change the colors of dropdown boxes and check boxes.
Example:
# highlight cell - row 3, column 5self.sheet.highlight( (3,5),bg="dark green",fg="white",)# or# same cells, background red, text color blacksheet[3,5].bg="red"sheet[3,5].fg="black"
Cells
highlight_cells(row:int|Literal["all"]=0,column:int|Literal["all"]=0,cells:list[tuple[int,int]]= [],canvas:Literal["table","index","header"]="table",bg:bool|None|str=False,fg:bool|None|str=False,redraw:bool=True,overwrite:bool=True,)->Sheet
Rows
highlight_rows(rows:Iterator[int]|int,bg:None|str=None,fg:None|str=None,highlight_index:bool=True,redraw:bool=True,end_of_screen:bool=False,overwrite:bool=True,)->Sheet
Columns
highlight_columns(columns:Iterator[int]|int,bg:bool|None|str=False,fg:bool|None|str=False,highlight_header:bool=True,redraw:bool=True,overwrite:bool=True,)->Sheet
If the highlights were created by a named span then the named span must be deleted, more informationhere.
Otherwise you can use either of the following methods to delete/remove highlights:
- Using a span method e.g.
span.dehighlight()more informationhere. - Using a sheet method e.g.
sheet.dehighlight(Span)details below:
dehighlight(*key:CreateSpanTypes,redraw:bool=True,)->Span
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.
Example:
# highlight column Bself.sheet.highlight("B",bg="dark green",fg="white",)# dehighlight column Bself.sheet.dehighlight("B")
Cells
dehighlight_cells(row:int|Literal["all"]=0,column:int=0,cells:list[tuple[int,int]]= [],canvas:Literal["table","row_index","header"]="table",all_:bool=False,redraw:bool=True,)->Sheet
Rows
dehighlight_rows(rows:list[int]|Literal["all"]= [],redraw:bool=True,)->Sheet
Columns
dehighlight_columns(columns:list[int]|Literal["all"]= [],redraw:bool=True,)->Sheet
All
dehighlight_all(cells:bool=True,rows:bool=True,columns:bool=True,header:bool=True,index:bool=True,redraw:bool=True,)->Sheet
Span objects (more informationhere) can be used to create dropdown boxes for cells, rows, columns, the entire sheet, headers and the index.
You can use either of the following methods:
- Using a span method e.g.
span.dropdown()more informationhere. - Using a sheet method e.g.
sheet.dropdown(Span)
Or if you need user inserted row/columns in the middle of areas with dropdown boxes to also have dropdown boxes you can use named spans, more informationhere.
Whether dropdown boxes are created for cells, rows or columns depends on thekind of span.
dropdown(*key:CreateSpanTypes,values:list= [],edit_data:bool=True,set_values:dict[tuple[int,int]|int,Any]|None=None,set_value:Any=None,state:Literal["normal","readonly","disabled"]="normal",redraw:bool=True,selection_function:Callable|None=None,modified_function:Callable|None=None,search_function:Callable=dropdown_search_function,validate_input:bool=True,text:None|str=None,)->Span
Notes:
selection_function/modified_function(Callable,None) parameters require eitherNoneor a function. 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.
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.valuesare the values to appear in a list view type interface when the dropdown box is open.edit_datawhenTruemakes edits in the table, header or index (depending on the span) based onset_values/set_value.set_valueswhen combined withedit_data=Trueallows adictto be provided of data coordinates (tuple[int, int]for a cell span orintfor a row/column span) askeys and values to set the cell at that coordinate to.- e.g.
set_values={(0, 0): "new value for A1"}. - The idea behind this parameter is that an entire column or row can have individual cell values and is not set to
set_valuealone.
- e.g.
set_valuewhen combined withedit_data=Truesets every cell in the span to the value provided.- If left as
Noneand ifset_valuesis alsoNonethen the topmost value fromvalueswill be used or if notvaluesthen"". - The same logic is applied when for example inserting a new row while having a column with dropdowns, the new value for the cell will be chosen in the same manner with
set_valueacting like a default value.
- If left as
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_namemodified_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.
Example:
# create dropdown boxes in column "D"self.sheet.dropdown("D",values=[0,1,2,3,4],)
If the dropdown boxes were created by a named span then the named span must be deleted, more informationhere.
Otherwise you can use either of the following methods to delete/remove dropdown boxes.
- Using a span method e.g.
span.del_dropdown()more informationhere. - Using a sheet method e.g.
sheet.del_dropdown(Span)details below:
del_dropdown(*key:CreateSpanTypes,redraw:bool=True,)->Span
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.
Example:
# create dropdown boxes in column "D"self.sheet.dropdown("D",values=[0,1,2,3,4],)# delete dropdown boxes in column "D"self.sheet.del_dropdown("D")
get_dropdown_values(r:int=0,c:int=0)->None|list
get_header_dropdown_values(c:int=0)->None|list
get_index_dropdown_values(r:int=0)->None|list
set_dropdown_values(r:int=0,c:int=0,set_existing_dropdown:bool=False,values:list= [],set_value:Any=None,)->Sheet
set_header_dropdown_values(c:int=0,set_existing_dropdown:bool=False,values:list= [],set_value:Any=None,)->Sheet
set_index_dropdown_values(r:int=0,set_existing_dropdown:bool=False,values:list= [],set_value:Any=None,)->Sheet
Parameters:
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:int,c:int,selection_function:str|Callable="",modified_function:str|Callable="",)->None|dict
header_dropdown_functions(c:int,selection_function:str|Callable="",modified_function:str|Callable="",)->None|dict
index_dropdown_functions(r:int,selection_function:str|Callable="",modified_function:str|Callable="",)->None|dict
get_dropdowns()->dict
Returns:
{(rowint,columnint): {'values':values,'select_function':selection_function,'modified_function':modified_function,'state':state,'text':text}}get_header_dropdowns()->dict
get_index_dropdowns()->dict
open_dropdown(r:int,c:int)->Sheet
open_header_dropdown(c:int)->Sheet
open_index_dropdown(r:int)->Sheet
close_dropdown(r:int|None=None,c:int|None=None)->Sheet
close_header_dropdown(c:int|None=None)->Sheet
close_index_dropdown(r:int|None=None)->Sheet
Notes:
- Also destroys any opened text editor windows.
Span objects (more informationhere) can be used to create check boxes for cells, rows, columns, the entire sheet, headers and the index.
You can use either of the following methods:
- Using a span method e.g.
span.checkbox()more informationhere. - Using a sheet method e.g.
sheet.checkbox(Span)
Or if you need user inserted row/columns in the middle of areas with check boxes to also have check boxes you can use named spans, more informationhere.
Whether check boxes are created for cells, rows or columns depends on thekind of span.
checkbox(*key:CreateSpanTypes,edit_data:bool=True,checked:bool|None=None,state:Literal["normal","disabled"]="normal",redraw:bool=True,check_function:Callable|None=None,text:str="",)->Span
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.edit_datawhenTrueedits the underlying cell data to eithercheckedifcheckedis aboolor tries to convert the existing cell data to abool.checkedis the initial creation value to set the box to, ifNonethen andedit_dataisTruethen it will try to convert the underlying cell data to abool.statecan be"normal"or"disabled". If"disabled"then color will be same as table grid lines, else it will be the cells text color.check_functioncan be used to trigger a function when the user clicks a checkbox.textdisplays text next to the checkbox in the cell, but will not be used as data, data will either beTrueorFalse.
Notes:
check_function(Callable,None) requires eitherNoneor a function. The function you use needs at least one argument because when the checkbox is set 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.
- To get the current checkbox value either:
- Get the cell data, more informationhere.
- Use the parameter
check_functionwith a function of your own creation to be called when the checkbox is set by the user.
Example:
self.sheet.checkbox("D",checked=True,)
If the check boxes were created by a named span then the named span must be deleted, more informationhere.
Otherwise you can use either of the following methods to delete/remove check boxes:
- Using a span method e.g.
span.del_checkbox()more informationhere. - Using a sheet method e.g.
sheet.del_checkbox(Span)details below:
del_checkbox(*key:CreateSpanTypes,redraw:bool=True,)->Span
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.
Example:
# creating checkboxes in column Dself.sheet.checkbox("D",checked=True,)# deleting checkboxes in column Dself.sheet.del_checkbox("D")
click_checkbox(*key:CreateSpanTypes,checked:bool|None=None,redraw:bool=True,)->Span
click_header_checkbox(c:int,checked:bool|None=None)->Sheet
click_index_checkbox(r:int,checked:bool|None=None)->Sheet
get_checkboxes()->dict
get_header_checkboxes()->dict
get_index_checkboxes()->dict
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.
Data 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.
- An full explanation of what arguments to use for the
formatter_optionsparameter can be foundhere. - A demonstration of all the built-in and custom formatters can be foundhere.
Span objects (more informationhere) can be used to format data for cells, rows, columns and the entire sheet.
You can use either of the following methods:
- Using a span method e.g.
span.format()more informationhere. - Using a sheet method e.g.
sheet.format(Span)
Or if you need user inserted row/columns in the middle of areas with data formatting to also be formatted you can use named spans, more informationhere.
Whether data is formatted for cells, rows or columns depends on thekind of span.
format(*key:CreateSpanTypes,formatter_options:dict= {},formatter_class:Any=None,redraw:bool=True,**kwargs,)->Span
Notes:
- 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.
- Data 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 displayed on the table GUI.
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.formatter_options(dict) a dictionary of keyword options/arguements to pass to the formatter, seehere for information on what argument to use.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.
If the data format rule was created by a named span then the named span must be deleted, more informationhere.
Otherwise you can use either of the following methods to delete/remove data formatting rules:
- Using a span method e.g.
span.del_format()more informationhere. - Using a sheet method e.g.
sheet.del_format(Span)details below:
del_format(*key:CreateSpanTypes,clear_values:bool=False,redraw:bool=True,)->Span
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.clear_values(bool) if true, all the cells covered by the span will have their values cleared.
del_all_formatting(clear_values:bool=False)->Sheet
clear_values(bool) if true, all the sheets cell values will be cleared.
reapply_formatting()->Sheet
- 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.
formatted(r:int,c:int)->dict
- If the cell is formatted function returns a
dictwith all the format keyword arguments. Thedictwill be empty if the cell is not formatted.
In addition to thegeneric formatter,tksheet provides formatters for many different data types.
A basic example showing how formatting some columns asfloat might be done:
importtkinterastkfromtksheetimport (Sheet,float_formatter,)fromtksheetimport (num2alpha,)classdemo(tk.Tk):def__init__(self):super().__init__()self.grid_columnconfigure(0,weight=1)self.grid_rowconfigure(0,weight=1)self.sheet=Sheet(self,data=[[f"{r}",f"{r}"]forrinrange(5)],expand_sheet_if_paste_too_big=True,theme="dark blue", )""" Format example """# some keyword arguments inside float_formatter()self.sheet.format(num2alpha(0),# column Aformatter_options=float_formatter(decimals=1,nullable=True, ), )# some keyword arguments outside# of float_formatter() insteadself.sheet.format("B",# column Bformatter_options=float_formatter(),decimals=3,nullable=False, )""" Rest of code """self.sheet.grid(row=0,column=0,sticky="nswe")self.sheet.enable_bindings("all","ctrl_select","edit_header","edit_index", )app=demo()app.mainloop()
You can use any of the following formatters as an argument for the parameterformatter_options.
A full list of keyword arguments available to these formatters is describedhere.
Theint_formatter is the basic configuration for a simple interger formatter.
int_formatter(datatypes:tuple[Any]|Any=int,format_function:Callable=to_int,to_str_function:Callable=to_str,invalid_value:Any="NaN",**kwargs,)->dict
Parameters:
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.- A full explanation of keyword arguments available is describedhere.
Example:
sheet.format_cell(0,0,formatter_options=tksheet.int_formatter())
Thefloat_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" ifdecimals = 1.
float_formatter(datatypes:tuple[Any]|Any=float,format_function:Callable=to_float,to_str_function:Callable=float_to_str,invalid_value:Any="NaN",decimals:int=2,**kwargs)->dict
Parameters:
format_function(function) a function that takes a string and returns afloat. By default, this is set to the in-builttksheet.to_float.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.- A full explanation of keyword arguments available is describedhere.
Example:
sheet.format_cell(0,0,formatter_options=tksheet.float_formatter(decimals=None))# A float formatter with maximum float() decimal places
Thepercentage_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%" ifdecimals = 1.
percentage_formatter(datatypes:tuple[Any]|Any=float,format_function:Callable=to_percentage,to_str_function:Callable=percentage_to_str,invalid_value:Any="NaN",decimals:int=0,**kwargs,)->dict
Parameters:
format_function(function) a function that takes a string and returns afloat. By default, this is set to the in-builttksheet.to_percentage. 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.- A full explanation of keyword arguments available is describedhere.
Example:
sheet.format_cell(0,0,formatter_options=tksheet.percentage_formatter(decimals=1))# A percentage formatter with 1 decimal place
Note:
By defaultpercentage_formatter() converts user entry21 to2100% and21% to21%. An example where21 is converted to21% instead is shown below:
# formats column A as percentage# uses:# format_function=alt_to_percentage# to_str_function=alt_percentage_to_strsheet.format("A",formatter_options=tksheet.percentage_formatter(format_function=alt_to_percentage,to_str_function=alt_percentage_to_str, ))
bool_formatter(datatypes:tuple[Any]|Any=bool,format_function:Callable=to_bool,to_str_function:Callable=bool_to_str,invalid_value:Any="NA",truthy:set=truthy,falsy:set=falsy,**kwargs,)->dict
Parameters:
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.- A full explanation of keyword arguments available is describedhere.
Example:
# A bool formatter with custom truthy and falsy values to account for aussie and kiwi slangsheet.format_cell(0,0,formatter_options=tksheet.bool_formatter(truthy=tksheet.truthy| {"nah yeah"},falsy=tksheet.falsy| {"yeah nah"}))
formatter(datatypes:tuple[Any]|Any,format_function:Callable,to_str_function:Callable=to_str,invalid_value:Any="NaN",nullable:bool=True,pre_format_function:Callable|None=None,post_format_function:Callable|None=None,clipboard_function:Callable|None=None,**kwargs,)->dict
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 theSheet() format functions as keyword arguments and are available as attributes for all formatters.
You can also provide functions of your own creation for all the below arguments which take functions if you require.
datatypes(tuple[Any], Any) 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.- Exceptions are suppressed (ignored) for this function. If an
Exception(error) occurs then it merely continues on to thepost_format_function(if it isCallable) and then finally returns the value.
- Exceptions are suppressed (ignored) for this function. If an
invalid_value(Any) is the value to display in the cell if the cell value'stypeis not indatatypes.invalid_valuemust have a__str__method - most python types do.- Pythons
isinstance()is used to determine thetype. invalid_valueis also relevant if usingSheetdata retrieval functions withtdisporget_displayedparameters asTrueas these retrieve the displayed value.- The cell's underlying value will not be set to
invalid_valueif it's invalid - it's only for display or displayed data retrieval.
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.- If the cell value's
typeis not indatatypesthen this function willnot be called, theinvalid_valuewill be returned instead. - If the cell's value is
Noneand the format hasnullable=Truethen this function willnot be called, an emptystrwill be returned instead.
- If the cell value's
nullable(bool) ifTruethen it guaranteestype(None)will be indatatypes, effectively allowing the cell's value to beNone.- When
Truejust before the givenformat_functionis run the cell's value is checked to see if it's in asetnamednonelike. You can import and modify thissetusingfrom tksheet import nonelike. If the value is innonelikethen it is set toNonebefore being sent to theformat_function. - When
Falsetype(None)is not allowed to be indatatypes. If the cell for some reason ends up asNonethen it will display as theinvalid_value. - When
Falsethe earlier describednonelikecheck does not occur.
- When
pre_format_function(function) This function is called before theformat_functionand can be used to modify the cells value before it is formatted usingformat_function. This can be useful, for example, if you want to strip out unwanted characters or convert a string to a different format before converting it to the desired datatype.- Exceptions are NOT suppressed for this function.
post_format_function(function) a function that takes a valuewhich 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.- Exceptions are NOT suppressed for this function.
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.- Exceptions are NOT suppressed for this function.
**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.
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 thedateutil package.
fromtksheetimport*fromdatetimeimportdatetime,datefromdateutil.parserimportparsedefto_local_datetime(dt,**kwargs):''' Our custom format_function, converts a string or a date to a datetime object in the local timezone. '''ifisinstance(dt,datetime):pass# Do nothingelifisinstance(dt,date):dt=datetime(dt.year,dt.month,dt.day)# Always good to account for unexpected inputselse:try:dt=parser.parse(dt)except:raiseValueError(f"Could not parse{dt} as a datetime")ifdt.tzinfoisNone:dt=dt.replace(tzinfo=tzlocal())# If no timezone is specified, assume local timezonedt=dt.astimezone(tzlocal())# Convert to local timezonereturndtdefdatetime_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. '''returndt.strftime(kwargs['format'])# Now we can create our custom formatter dictionary from the generic formatter interface in tksheetdatetime_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 sheet.format() or span.format() just like any other formatter
For those wanting even more customisation of their formatters there is also 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 oftksheet.Formatter and override the methods to customise. This custom class can then be passed to theformat_cells()formatter_class parameter.
Span objects (more informationhere) can be used to create readonly rules for cells, rows, columns, the entire sheet, headers and the index.
You can use either of the following methods:
- Using a span method e.g.
span.readonly()more informationhere. - Using a sheet method e.g.
sheet.readonly(Span)
Or if you need user inserted row/columns in the middle of areas with a readonly rule to also have a readonly rule you can use named spans, more informationhere.
Whether cells, rows or columns are readonly depends on thekind of span.
readonly(*key:CreateSpanTypes,readonly:bool=True,)->Span
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.readonly(bool)Trueto create a rule andFalseto delete one created without the use of named spans.
If the readonly rule was created by a named span then the named span must be deleted, more informationhere.
Otherwise you can use either of the following methods to delete/remove readonly rules:
- Using a span method e.g.
span.readonly()with the keyword argumentreadonly=Falsemore informationhere. - Using a sheet method e.g.
sheet.readonly(Span)with the keyword argumentreadonly=Falseexample below:
# creating a readonly ruleself.sheet.readonly(self.sheet.span("A",header=True),readonly=True,)# deleting the readonly ruleself.sheet.readonly(self.sheet.span("A",header=True),readonly=False,)
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.readonly(bool)Trueto create a rule andFalseto delete one created without the use of named spans.
- Font arguments require a three tuple e.g.
("Arial", 12, "normal")or("Arial", 12, "bold")or("Arial", 12, "italic").
Set the table font
font(newfont:tuple[str,int,str]|None=None)->tuple[str,int,str]
Set the index font
index_font(newfont:tuple[str,int,str]|None=None)->tuple[str,int,str]
Set the header font
header_font(newfont:tuple[str,int,str]|None=None)->tuple[str,int,str]
Set the in-built popup menu font
popup_menu_font(newfont:tuple[str,int,str]|None=None)->tuple[str,int,str]
There are functions to set the text alignment for specific cells/rows/columns and also functions to set the text alignment for a whole part of the sheet (table/index/header).
- Alignment argument (
str) options are:"w","west","left""e","east","right""c","center","centre"
Unfortunately vertical alignment is not available.
Set the text alignment for the whole of the table (doesn't include index/header).
table_align(align:str=None,redraw:bool=True,)->str|Sheet
Set the text alignment for the whole of the header.
header_align(align:str=None,redraw:bool=True,)->str|Sheet
Set the text alignment for the whole of the index.
row_index_align(align:str=None,redraw:bool=True,)->str|Sheet# can also use index_align() which behaves the same
The following function is for setting text alignment for specific cells, rows or columns in the table, header and index.
Span objects (more informationhere) can be used to create text alignment rules for cells, rows, columns, the entire sheet, headers and the index.
You can use either of the following methods:
- Using a span method e.g.
span.align()more informationhere. - Using a sheet method e.g.
sheet.align(Span)
Or if you need user inserted row/columns in the middle of areas with an alignment rule to also have an alignment rule you can use named spans, more informationhere.
Whether cells, rows or columns are affected depends on thekind of span.
align(*key:CreateSpanTypes,align:str|None=None,redraw:bool=True,)->Span
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.align(str,None) must be one of the following:"w","west","left""e","east","right""c","center","centre"
If the text alignment rule was created by a named span then the named span must be deleted, more informationhere.
Otherwise you can use either of the following methods to delete/remove specific text alignment rules:
- Using a span method e.g.
span.del_align()more informationhere. - Using a sheet method e.g.
sheet.del_align(Span)details below:
del_align(*key:CreateSpanTypes,redraw:bool=True,)->Span
Parameters:
key(CreateSpanTypes) either a span or a type which can create a span. Seehere for more information on the types that can create a span.
Cell text alignments:
get_cell_alignments()->dict
Row text alignments:
get_row_alignments()->dict
Column text alignments:
get_column_alignments()->dict
The below functions can be used to retrieve cell options/properties such as highlights, format, readonly etc.
Retrieve options for a single cell in the main table. Also retrieves any row/column options impacting that cell.
props(row:int,column:int|str,key:None|Literal["format","highlight","dropdown","checkbox","readonly","align","note", ]=None,cellops:bool=True,rowops:bool=True,columnops:bool=True,)->dict
Parameters:
rowonlyint.columnintorstre.g."A"is index0.key:- If left as
Nonethen all existing properties for that cell will be returned in adict. - If using a
stre.g."highlight"it will only look for highlight properties for that cell.
- If left as
cellopswhenTruewill look for cell options for the cell.rowopswhenTruewill look for row options for the cell.columnopswhenTruewill look for column options for the cell.
Example:
# making column B, including header read onlysheet.readonly(sheet["B"].options(header=True))# checking if row 0, column 1 (B) is readonly:cell_is_readonly=sheet.props(0,1,"readonly")# can also use a string for the column:cell_is_readonly=sheet.props(0,"b","readonly")
Retrieve options for a single cell in the index.
index_props(row:int,key:None|Literal["format","highlight","dropdown","checkbox","readonly","align","note", ]=None,)->dict
Parameters:
rowonlyint.key:- If left as
Nonethen all existing properties for that cell will be returned in adict. - If using a
stre.g."highlight"it will only look for highlight properties for that cell.
- If left as
Retrieve options for a single cell in the header.
header_props(column:int|str,key:None|Literal["format","highlight","dropdown","checkbox","readonly","align","note", ]=None,)->dict
Parameters:
columnonlyint.key:- If left as
Nonethen all existing properties for that cell will be returned in adict. - If using a
stre.g."highlight"it will only look for highlight properties for that cell.
- If left as
Get internal storage dictionary of highlights, readonly cells, dropdowns etc. Specifically for cell options.
get_cell_options(key:None|str=None,canvas:Literal["table","row_index","header"]="table")->dict
Get internal storage dictionary of highlights, readonly rows, dropdowns etc. Specifically for row options.
get_row_options(key:None|str=None)->dict
Get internal storage dictionary of highlights, readonly columns, dropdowns etc. Specifically for column options.
get_column_options(key:None|str=None)->dict
Get internal storage dictionary of highlights, readonly header cells, dropdowns etc. Specifically for header options.
get_header_options(key:None|str=None)->dict
Get internal storage dictionary of highlights, readonly row index cells, dropdowns etc. Specifically for row index options.
get_index_options(key:None|str=None)->dict
Delete any formats, alignments, dropdown boxes, check boxes, highlights etc. that are larger than the sheets currently held data, includes row index and header in measurement of dimensions.
del_out_of_bounds_options()->Sheet
Delete all alignments, dropdown boxes, check boxes, highlights etc.
reset_all_options()->Sheet
All selected cell/box getting functions return or generatedisplayed cell coordinates.
- Displayed cell coordinates ignore hidden rows/columns when indexing cells.
- Data cell coordinates include hidden rows/columns in indexing cells.
This is always a single cell of displayed indices. If you have hidden rows or columns you can change the integers to data indices using the following functions:
get_currently_selected()->tuple|Selected
Notes:
- Returns either:
namedtupleof(row, column, type_, box, iid, fill_iid).type_can be"rows","columns"or"cells".boxtuple[int, int, int, int]are the coordinates of the box that the currently selected box is attached to.(from row, from column, up to but not including row, up to but not including column).
iidis the canvas item id of the currently selected box.fill_iidis the canvas item id of the box that the currently selected box is attached to.
- An empty
tupleif nothing is selected.
- Can also use
sheet.selectedas shorter@propertyversion of the function.
Example:
currently_selected=self.sheet.get_currently_selected()ifcurrently_selected:row=currently_selected.rowcolumn=currently_selected.columntype_=currently_selected.type_ifself.sheet.selected: ...
get_selected_rows(get_cells:bool=False,get_cells_as_rows:bool=False,return_tuple:bool=False,)->tuple[int]|tuple[tuple[int,int]]|set[int]|set[tuple[int,int]]
- Returns displayed indexes.
get_selected_columns(get_cells:bool=False,get_cells_as_columns:bool=False,return_tuple:bool=False,)->tuple[int]|tuple[tuple[int,int]]|set[int]|set[tuple[int,int]]
- Returns displayed indexes.
get_selected_cells(get_rows:bool=False,get_columns:bool=False,sort_by_row:bool=False,sort_by_column:bool=False,reverse:bool=False,)->list[tuple[int,int]]|set[tuple[int,int]]
- Returns displayed coordinates.
gen_selected_cells(get_rows:bool=False,get_columns:bool=False,)->Generator[tuple[int,int]]
- Generates displayed coordinates.
get_all_selection_boxes()->tuple[tuple[int,int,int,int]]
- Returns displayed coordinates.
get_all_selection_boxes_with_types()->list[tuple[tuple[int,int,int,int],str]]
Equivalent toget_all_selection_boxes_with_types() but shortened as@property.
@propertyboxes()->list[tuple[tuple[int,int,int,int],str]]
cell_selected(r:int,c:int,rows:bool=False,columns:bool=False,)->bool
rowsifTruealso checks if provided cell is part of a selected row.columnsifTruealso checks if provided cell is part of a selected column.
row_selected(r:int,cells:bool=False)->bool
cellsifTruealso checks if provided row is selected as part of a cell selection box.
column_selected(c:int,cells:bool=False)->bool
cellsifTruealso checks if provided column is selected as part of a cell selection box.
anything_selected(exclude_columns:bool=False,exclude_rows:bool=False,exclude_cells:bool=False,)->bool
all_selected()->bool
get_ctrl_x_c_boxes(nrows:bool=True)->tuple[dict[tuple[int,int,int,int],str],int]
@propertyctrl_boxes()->dict[tuple[int,int,int,int],str]
get_selected_min_max()->tuple[int,int,int,int]|tuple[None,None,None,None]
- returns
(min_y, min_x, max_y, max_x)of any selections including rows/columns.
All selected cell/box setting functions usedisplayed cell coordinates.
- Displayed cell coordinates ignore hidden rows/columns when indexing cells.
- Data cell coordinates include hidden rows/columns in indexing cells.
set_currently_selected(row:int|None=None,column:int|None=None)->Sheet
select_row(row:int,redraw:bool=True,run_binding_func:bool=True)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"row_select"bound.
select_column(column:int,redraw:bool=True,run_binding_func:bool=True)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"column_select"bound.
select_cell(row:int,column:int,redraw:bool=True,run_binding_func:bool=True)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"cell_select"bound.
select_all(redraw:bool=True,run_binding_func:bool=True)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"select_all"bound.
Deselect a specific cell, row or column.
deselect(row:int|None|Literal["all"]=None,column:int|None=None,cell:tuple|None=None,redraw:bool=True,)->Sheet
- Leave parameters as
None, orrowas"all"to deselect everything. - Can also close text editors and open dropdowns.
Deselect any cell, row or column selection box conflicting withrows and/orcolumns.
deselect_any(rows:Iterator[int]|int|None,columns:Iterator[int]|int|None,redraw:bool=True,)->Sheet
- Leave parameters as
Noneto deselect everything. - Can also close text editors and open dropdowns.
add_cell_selection(row:int,column:int,redraw:bool=True,run_binding_func:bool=True,set_as_current:bool=True,)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"cell_select"bound.
add_row_selection(row:int,redraw:bool=True,run_binding_func:bool=True,set_as_current:bool=True,)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"row_select"bound.
add_column_selection(column:int,redraw:bool=True,run_binding_func:bool=True,set_as_current:bool=True,)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"column_select"bound.
toggle_select_cell(row:int,column:int,add_selection:bool=True,redraw:bool=True,run_binding_func:bool=True,set_as_current:bool=True,)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"cell_select"bound.
toggle_select_row(row:int,add_selection:bool=True,redraw:bool=True,run_binding_func:bool=True,set_as_current:bool=True,)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"row_select"bound.
toggle_select_column(column:int,add_selection:bool=True,redraw:bool=True,run_binding_func:bool=True,set_as_current:bool=True,)->Sheet
run_binding_funcis only relevant if you haveextra_bindings()with"column_select"bound.
create_selection_box(r1:int,c1:int,r2:int,c2:int,type_:str="cells",)->int
type_either"cells"or"rows"or"columns".- Returns the canvas item id for the box.
@boxes.setterboxes(boxes:Sequence[tuple[tuple[int,int,int,int],str]])
- Can be used to set the Sheets selection boxes, deselects everything before setting.
Example:
sheet.boxes= [ ((0,0,3,3),"cells"), ((4,0,5,10),"rows"),]
- The above would select a cells box from cell
A1up to and including cellC3and row4(in python index,5as excel index) where the sheet has 10 columns. - The
strin the type hint should be either"cells"or"rows"or"columns".
recreate_all_selection_boxes()->Sheet
To enable auto resizing of columns to the Sheet window useset_options() with the keyword argumentauto_resize_columns. This argument can either be anint orNone. If set as anint the columns will automatically resize to fit the width of the window, theint value being the minimum of each column in pixels. IfNone it will disable the auto resizing. Example:
# auto resize columns, column minimum width set to 150 pixelsset_options(auto_resize_columns=150)
To enable auto resizing of rows to the Sheet window useset_options() with the keyword argumentauto_resize_rows. This argument can either be anint orNone. If set as anint the rows will automatically resize to fit the width of the window, theint value being the minimum of each row in pixels. IfNone it will disable the auto resizing. Example:
# auto resize rows, row minimum width set to 30 pixelsset_options(auto_resize_rows=30)
default_column_width(width:int|None=None)->int
width(int,None) use anintto set the width in pixels,Nonedoes not set the width.
default_row_height(height:int|str|None=None)->int
height(int,str,None) use a numericalstrfor number of lines e.g."3"for a height that fits 3 lines ORintfor pixels.
default_header_height(height:int|str|None=None)->int
height(int,str,None) use a numericalstrfor number of lines e.g."3"for a height that fits 3 lines orintfor pixels.
set_cell_size_to_text(row:int,column:int,only_set_if_too_small:bool=False,redraw:bool=True,)->Sheet
set_all_cell_sizes_to_text(redraw:bool=True,width:int|None=None,slim:bool=False,)->tuple[list[float],list[float]]
- Returns the Sheets row positions and column positions in that order.
widtha minimum width for all column widths set using this function.slimcolumn widths will be set precisely to text width and not add any extra space.
set_all_column_widths(width:int|None=None,only_set_if_too_small:bool=False,redraw:bool=True,recreate_selection_boxes:bool=True,)->Sheet
width(int,None) leaveNoneto set to cell text sizes for each column.
set_all_row_heights(height:int|None=None,only_set_if_too_small:bool=False,redraw:bool=True,recreate_selection_boxes:bool=True,)->Sheet
height(int,None) leaveNoneto set to cell text sizes for each row.
column_width(column:int|Literal["all","displayed"]|None=None,width:int|Literal["default","text"]|None=None,only_set_if_too_small:bool=False,redraw:bool=True,)->Sheet|int
row_height(row:int|Literal["all","displayed"]|None=None,height:int|Literal["default","text"]|None=None,only_set_if_too_small:bool=False,redraw:bool=True,)->Sheet|int
get_column_widths(canvas_positions:bool=False)->list[float]
canvas_positions(bool) gets the actual canvas x coordinates of column lines.
get_row_heights(canvas_positions:bool=False)->list[float]
canvas_positions(bool) gets the actual canvas y coordinates of row lines.
get_row_text_height(row:int,visible_only:bool=False,only_if_too_small:bool=False,)->int
- Returns a height in pixels which will fit all text in the specified row.
visible_onlyifTrueonly measures rows visible on the Sheet.only_if_too_smallifTruewill only return a new height if the current row height is too short to accomodate its text.
get_column_text_width(column:int,visible_only:bool=False,only_if_too_small:bool=False,)->int
- Returns a width in pixels which will fit all text in the specified column.
visible_onlyifTrueonly measures columns visible on the Sheet.only_if_too_smallifTruewill only return a new width if the current column width is too thin to accomodate its text.
set_column_widths(column_widths:Iterator[int,float]|None=None,canvas_positions:bool=False,reset:bool=False,)->Sheet
set_row_heights(row_heights:Iterator[int,float]|None=None,canvas_positions:bool=False,reset:bool=False,)->Sheet
set_width_of_index_to_text(text:None|str=None,*args,**kwargs)->Sheet
text(str,None) provide astrto set the width to or useNoneto set it to existing values in the index.
set_index_width(pixels:int,redraw:bool=True)->Sheet
- Note that it disables auto resizing of index. Use
set_options()to restore auto resizing.
set_height_of_header_to_text(text:None|str=None)->Sheet
text(str,None) provide astrto set the height to or useNoneto set it to existing values in the header.
set_header_height_pixels(pixels:int,redraw:bool=True)->Sheet
set_header_height_lines(nlines:int,redraw:bool=True)->Sheet
del_column_position(idx:int,deselect_all:bool=False)->Sheetdel_column_positions(idxs:Iterator[int]|None=None)->Sheet
del_row_position(idx:int,deselect_all:bool=False)->Sheetdel_row_positions(idxs:Iterator[int]|None=None)->Sheet
insert_row_position(idx:Literal["end"]|int="end",height:int|None=None,deselect_all:bool=False,redraw:bool=False,)->Sheet
insert_column_position(idx:Literal["end"]|int="end",width:int|None=None,deselect_all:bool=False,redraw:bool=False,)->Sheet
insert_row_positions(idx:Literal["end"]|int="end",heights:Sequence[float]|int|None=None,deselect_all:bool=False,redraw:bool=False,)->Sheet
insert_column_positions(idx:Literal["end"]|int="end",widths:Sequence[float]|int|None=None,deselect_all:bool=False,redraw:bool=False,)->Sheet
sheet_display_dimensions(total_rows:int|None=None,total_columns:int|None=None,)->tuple[int,int]|Sheet
move_row_position(row:int,moveto:int)->Sheet
move_column_position(column:int,moveto:int)->Sheet
get_example_canvas_column_widths(total_cols:int|None=None)->list[float]
get_example_canvas_row_heights(total_rows:int|None=None)->list[float]
verify_row_heights(row_heights:list[float],canvas_positions:bool=False)->bool
verify_column_widths(column_widths:list[float],canvas_positions:bool=False)->bool
valid_row_height(height:int)->int
valid_column_width(width:int)->int
@propertyvisible_rows()->tuple[int,int]
- Returns start row, end row
- e.g.
start_row, end_row = sheet.visible_rows
@propertyvisible_columns()->tuple[int,int]
- Returns start column, end column
- e.g.
start_column, end_column = sheet.visible_columns
The below functions require a mouse click event, for example you could bind right click, examplehere, and then identify where the user has clicked.
Determine if a tkevent.widget is theSheet.
event_widget_is_sheet(event:Any,table:bool=True,index:bool=True,header:bool=True,top_left:bool=True,)->bool
Notes:
- Parameters set to
Truewill include events that occurred within that widget.- e.g. If an event occurs in the top left corner of the sheet but the parameter
top_leftisFalsethe function will returnFalse.
- e.g. If an event occurs in the top left corner of the sheet but the parameter
Check if any Sheet widgets have focus.
has_focus()->bool:
- Includes child widgets such as scroll bars.
identify_region(event:Any)->Literal["table","index","header","top left"]
identify_row(event:Any,exclude_index:bool=False,allow_end:bool=True,)->int|None
identify_column(event:Any,exclude_header:bool=False,allow_end:bool=True,)->int|None
For example:sheet.bind("<Control-B>", sheet.paste)
cut(event:Any=None,validation:bool=True)->None|EventDataDictpaste(event:Any=None,validation:bool=True)->None|EventDataDictdelete(event:Any=None,validation:bool=True)->None|EventDataDictcopy(event:Any=None)->None|EventDataDictundo(event:Any=None)->None|EventDataDictredo(event:Any=None)->None|EventDataDict
validation(bool) whenFalsedisables any boundedit_validation()function from running.
sync_scroll(widget:Any)->Sheet
- Sync scroll positions between
Sheets, may or may not work with other widgets. Uses scrollbar positions.
Syncing two sheets:
self.sheet1.sync_scroll(self.sheet2)
Syncing three sheets:
# syncs sheet 1 and 2 between each otherself.sheet1.sync_scroll(self.sheet2)# syncs sheet 1 and 3 between each otherself.sheet1.sync_scroll(self.sheet3)# syncs sheet 2 and 3 between each otherself.sheet2.sync_scroll(self.sheet3)
unsync_scroll(widget:Any=None)->Sheet
- Leaving
widgetasNoneunsyncs all previously synced widgets.
see(row:int=0,column:int=0,keep_yscroll:bool=False,keep_xscroll:bool=False,bottom_right_corner:bool|None=None,check_cell_visibility:bool=True,redraw:bool=True,)->Sheet
cell_visible(r:int,c:int)->bool
cell_completely_visible(r:int,c:int,seperate_axes:bool=False)->bool
separate_axesreturns tuple of bools e.g.(cell y axis is visible, cell x axis is visible)
set_xview(position:None|float=None,option:str="moveto")->Sheet|tuple[float,float]
Notes:
- If
positionisNonethentuple[float, float]of main tablexview()is returned. xviewandxview_movetohave the same behaviour.
set_yview(position:None|float=None,option:str="moveto")->Sheet|tuple[float,float]
- If
positionisNonethentuple[float, float]of main tableyview()is returned. yviewandyview_movetohave the same behaviour.
get_xview()->tuple[float,float]
get_yview()->tuple[float,float]
set_view(x_args: [str,float],y_args: [str,float])->Sheet
Note that once you have hidden columns you can use the functiondisplayed_column_to_data(column) to retrieve a column data index from a displayed index.
display_columns(columns:None|Literal["all"]|Iterator[int]=None,all_columns_displayed:None|bool=None,reset_col_positions:bool=True,refresh:bool=False,redraw:bool=False,deselect_all:bool=True,**kwargs,)->list[int]|None
Parameters:
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.
Examples:
# display all columnsself.sheet.display_columns("all")# displaying specific columns onlyself.sheet.display_columns([2,4,7],all_displayed=False)
Get the bool
@propertyall_columns()
- e.g.
get_all_columns_displayed = sheet.all_columns.
Set the bool
@all_columns.setterall_columns(a:bool)
e.g.sheet.all_columns = True.
all_columns_displayed(a:bool|None=None)->bool
a(bool,None) Either set by usingboolor get by leavingNonee.g.all_columns_displayed().
hide_columns(columns:int|set|Iterator[int]=set(),redraw:bool=True,deselect_all:bool=True,data_indexes:bool=False,)->Sheet
Parameters:
- NOTE:
columns(int) by default 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 used in conjunction withget_selected_columns(). data_indexeswhenFalseit makes thecolumnsparameter indexes represent displayed columns and not the underlying Sheet data columns. WhenTruethe indexes represent data indexes.
Example:
columns_to_hide=set(sheet.data_c(c)forcinsheet.get_selected_columns())sheet.hide_columns(columns_to_hide,data_indexes=True,)
show_columns(columns:int|Iterator[int],redraw:bool=True,deselect_all:bool=True,)->Sheet
Parameters:
- NOTE:
columns(int) uses data column indexes, not displayed indexes. In other words the indexes of the columns which represent the underlying data are shown.
Notes:
- Will return if all columns are currently displayed (
Sheet.all_columns).
Example:
# converting displayed column indexes to data indexes using data_c(c)columns=set(sheet.data_c(c)forcinsheet.get_selected_columns())# hiding columnssheet.hide_columns(columns,data_indexes=True,)# showing them againsheet.show_columns(columns)
Convert a displayed column index to a data index. If the internalall_columns_displayed attribute isTrue then it will return the provided argument.
displayed_column_to_data(c)data_c(c)
@propertydisplayed_columns()->list[int]
- e.g.
columns = sheet.displayed_columns
Note that once you have hidden rows you can use the functiondisplayed_row_to_data(row) to retrieve a row data index from a displayed index.
display_rows(rows:None|Literal["all"]|Iterator[int]=None,all_rows_displayed:None|bool=None,reset_row_positions:bool=True,refresh:bool=False,redraw:bool=False,deselect_all:bool=True,**kwargs,)->list[int]|None
Parameters:
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.
Examples:
- An example of row filtering using this function can be foundhere.
- More examples below:
# display all rowsself.sheet.display_rows("all")# display specific rows onlyself.sheet.display_rows([2,4,7],all_displayed=False)
hide_rows(rows:int|set|Iterator[int]=set(),redraw:bool=True,deselect_all:bool=True,data_indexes:bool=False,)->Sheet
Parameters:
- NOTE:
rows(int) by default 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 used in conjunction withget_selected_rows(). data_indexeswhenFalseit makes therowsparameter indexes represent displayed rows and not the underlying Sheet data rows. WhenTruethe indexes represent data indexes.
Example:
rows_to_hide=set(sheet.data_r(r)forrinsheet.get_selected_rows())sheet.hide_rows(rows_to_hide,data_indexes=True,)
show_rows(rows:int|Iterator[int],redraw:bool=True,deselect_all:bool=True,)->Sheet
Parameters:
- NOTE:
rows(int) uses data row indexes, not displayed indexes. In other words the indexes of the rows which represent the underlying data are shown.
Notes:
- Will return if all rows are currently displayed (
Sheet.all_rows).
Example:
# converting displayed row indexes to data indexes using data_r(r)rows=set(sheet.data_r(r)forrinsheet.get_selected_rows())# hiding rowssheet.hide_rows(rows,data_indexes=True,)# showing them againsheet.show_rows(rows)
Get the bool
@propertyall_rows()
- e.g.
get_all_rows_displayed = sheet.all_rows.
Set the bool
@all_rows.setterall_rows(a:bool)
e.g.sheet.all_rows = True.
all_rows_displayed(a:bool|None=None)->bool
a(bool,None) Either set by usingboolor get by leavingNonee.g.all_rows_displayed().
Convert a displayed row index to a data index. If the internalall_rows_displayed attribute isTrue then it will return the provided argument.
displayed_row_to_data(r)data_r(r)
@propertydisplayed_rows()->list[int]
- e.g.
rows = sheet.displayed_rows
hide(canvas:Literal["all","row_index","header","top_left","x_scrollbar","y_scrollbar", ]="all",)->Sheet
canvas(str) options areall,row_index,header,top_left,x_scrollbar,y_scrollbarallhides the entire table and is the default.
show(canvas:Literal["all","row_index","header","top_left","x_scrollbar","y_scrollbar", ]="all",)->Sheet
canvas(str) options areall,row_index,header,top_left,x_scrollbar,y_scrollbarallshows the entire table and is the default.
height_and_width(height:int|None=None,width:int|None=None,)->Sheet
height(int,None) set a height in pixels.width(int,None) set a width in pixels.If both arguments areNonethen table will reset to default tkinter canvas dimensions.
get_frame_y(y:int)->int
- Adds the height of the Sheets header to a y position.
get_frame_x(x:int)->int
- Adds the width of the Sheets index to an x position.
open_cell(ignore_existing_editor:bool=True)->Sheet
- 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:bool=True)->Sheet
- Also uses currently selected cell, which you can set with
set_currently_selected().
open_index_cell(ignore_existing_editor:bool=True)->Sheet
- Also uses currently selected cell, which you can set with
set_currently_selected().
Table:
set_text_editor_value(text:str="",)->Sheet
Index:
set_index_text_editor_value(text:str="",)->Sheet
Header:
set_header_text_editor_value(text:str="",)->Sheet
close_text_editor(set_data:bool=True)->Sheet
Notes:
- Closes any open text editors, including header and index.
- Also closes any existing
"normal"state dropdown box.
Parameters:
set_data(bool) whenTruesets the cell data to the text editor value (if it is valid). WhenFalsethe text editor is closed without setting data.
get_text_editor_value()->str|None
Notes:
Noneis returned if no text editor exists, astrof the text editors value will be returned if it does.
destroy_text_editor(event:Any=None)->Sheet
get_text_editor_widget(event:Any=None)->tk.Text|None
bind_key_text_editor(key:str,function:Callable)->Sheet
unbind_key_text_editor(key:str)->Sheet
tksheet has a treeview mode which behaves similarly to the ttk treeview widget, it is not a drop in replacement for it though.
Always either use a freshSheet() instance or useSheet.reset() before enabling treeview mode.
- When treeview mode is enabled the row index is a
listofNodeobjects. The row index should not be modified by the usualrow_index()function. - Most other tksheet functions should work as normal.
- The index text alignment must be
"w"aka west or left.
You can make a treeview mode sheet by using the initialization parametertreeview:
sheet=Sheet(parent,treeview=True)
Or by usingSheet.reset() andSheet.set_options().
my_sheet.reset()my_sheet.set_options(treeview=True)
See the other sections on sheet initialization and examples for the other usualSheet() parameters.
Functions designed for use with treeview mode.
insert(parent:str="",index:None|int|Literal["end"]=None,iid:None|str=None,text:None|str=None,values:None|list[Any]=None,create_selections:bool=False,undo:bool=True,)->str
Parameters:
parentis theiidof the parent item (if any). If left as""then the item will not have a parent.indexis the row number for the item to be placed at, leave asNonefor the end.iidis a new and unique item id. It will be generated automatically if left asNone.textis the displayed text in the row index for the item.valuesis a list of values which will become the items row in the sheet.create_selectionswhenTrueselects the row that has just been created.undowhenTrueadds the change to the undo stack.
Notes:
- Returns the
iid.
Example:
sheet.insert(iid="top level",text="Top level",values=["cell A1","cell B1"],)sheet.insert(parent="top level",iid="mid level",text="Mid level",values=["cell A2","cell B2"],)
bulk_insert(data:list[list[Any]],parent:str="",index:None|int|Literal["end"]=None,iid_column:int|None=None,text_column:int|None|str=None,create_selections:bool=False,include_iid_column:bool=True,include_text_column:bool=True,undo:bool=True,)->dict[str,int]
Parameters:
parentis theiidof the parent item (if any). If left as""then the items will not have a parent.indexis the row number for the items to be placed at, leave asNonefor the end.iid_columnif left asNoneiids will be automatically generated for the new items, else you can specify a column in thedatawhich contains the iids.text_column:- If left as
Nonethere will be no displayed text next to the items. - A text column can be provided in the data and
text_columnset to anintrepresenting its index to provide the displayed text for the items. - Or if a
stris used all items will have thatstras their displayed text.
- If left as
create_selectionswhenTrueselects the row that has just been created.include_iid_columnwhenFalseexcludes the iid column from the inserted rows.include_text_columnwhen thetext_columnis anintsetting this toFalseexcludes that column from the treeview.undowhenTrueadds the change to the undo stack.
Notes:
- Returns a
dict[str, int]of key: new iids, value: their data row number.
Example:
sheet.insert(iid="ID-1",text="ID-1",values=["ID 1 Value"])sheet.bulk_insert(data=[ ["CID-1","CID 1 Value"], ["CID-2","CID 2 Value"], ],parent="ID-1",iid_column=0,text_column=0,include_iid_column=False,include_text_column=False,)
This takes a list of lists where sublists are rows and a few arguments to bulk insert items into the treeview.Note that:
- It resets the sheet so cannot be used to bulk add to an already existing treeview.
tree_build(data:list[list[Any]],iid_column:int,parent_column:int,text_column:None|int=None,push_ops:bool=False,row_heights:Sequence[int]|None|False=None,open_ids:Iterator[str]|None=None,safety:bool=True,ncols:int|None=None,lower:bool=False,include_iid_column:bool=True,include_parent_column:bool=True,include_text_column:bool=True,)->Sheet
Parameters:
dataa list of lists, one column must be an iid column, another must be a parent iid column.text_columnif anintis used then the values in that column will populate the row index.push_opswhenTruethe newly inserted rows will push all existing sheet options such as highlights downwards.row_heightsalistofints can be used to provide the displayed row heights in pixels (does not include hidden items). Only use if you know what you're doing here.open_idsa list of iids which will be opened.safetywhenTruechecks for infinite loops, empty iid cells and duplicate iids. No error or warning will be generated.- In the case of infinite loops the parent iid cell will be cleared.
- In the case of empty iid cells the row will be ignored.
- In the case of duplicate iids they will be renamed and
"DUPLICATED_<number>"will be attached to the end.
ncolsis like maximum columns, anintwhich limits the number of columns that are included in the loaded data.lowermakes all item ids - iids lower case.include_iid_columnwhenFalseexcludes the iid column from the inserted rows.include_parent_columnwhenFalseexcludes the parent column from the inserted rows.include_text_columnwhen thetext_columnis anintsetting this toFalseexcludes that column from the treeview.
Notes:
- Returns the
Sheetobject.
Example:
data= [ ["id1","","id1 val"], ["id2","id1","id2 val"],]sheet.tree_build(data=data,iid_column=0,parent_column=1,include_iid_column=False,include_parent_column=False,)
tree_reset()->Sheet
tree_get_open()->set[str]
tree_set_open(open_ids:Iterator[str])->Sheet
- Any other iids are closed as a result.
tree_open(*items,redraw:bool=True)->Sheet
- Opens all given iids.
tree_close(*items,redraw:bool=True)->Sheet
- Closes all given iids.
item(item:str,iid:str|None=None,text:str|None=None,values:list|None=None,open_:bool|None=None,undo:bool=True,emit_event:bool=True,redraw:bool=True,)->DotDict|Sheet
Parameters:
itemiid, required argument.iiduse astrto rename the iid.textuse astrto get the iid new display text in the row index.valuesuse alistof values to give the item a new row of values (does not include row index).open_use aboolto set the item as open or closed.Falseis closed.undoadds any changes to the undo stack.emit_eventemits a<<SheetModified>>event if changes were made.
Notes:
- If no arguments are given a
DotDictis returned with the item attributes.
{"text": ...,"values": ...,"open_": ...,}itemrow(item:str)->int
- Includes hidden rows in counting row numbers.
rowitem(row:int,data_index:bool=False)->str|None
- Includes hidden rows in counting row numbers. Seehere for more information.
get_children(item:None|str=None)->Generator[str]
item:- When left as
Nonewill return all iids currently in treeview, including hidden rows. - Use an empty
str("") to get all top level iids in the treeview. - Use an iid to get the children for that particular iid. Does not include all descendants.
- When left as
tree_traverse(item:None|str=None)->Generator[str]:
- Exactly the same as above but instead of retrieving iids from the index list it gets top iids and uses traversal to iterate through descendants.
descendants(item:str,check_open:bool=False)->Generator[str]:
- Returns a generator which yields item ids in depth first order.
@propertytree_selected()->str|None:
- Returns the item id of the currently selected box row. If nothing is selected returns
None.
del_items(*items,undo:bool=True)->Sheet
*itemsthe iids of items to delete.- Also deletes all item descendants.
set_children(parent:str,*newchildren:str,index:int|None=None,select:bool=True,undo:bool=True,emit_event:bool=False,)->Sheet
parentthe new parent for the items.*newchildrenthe items to move.
move(item:str,parent:str,index:int|None=None,select:bool=True,undo:bool=True,emit_event:bool=False,)->tuple[dict[int,int],dict[int,int],EventDataDict]
Parameters:
itemis the iid to move.parentis the new parent for the item.- Use an empty
str("") to move the item to the top.
- Use an empty
index:- Leave as
Noneto move to item to the end of the top/children. - Use an
intto move the item to an index within its parents children (or within top level items if moving to the top).
- Leave as
selectwhenTrueselects the moved rows.undowhenTrueadds the change to the undo stack.emit_eventwhenTrueemits events related to sheet modification.
Notes:
- Also moves all of the items descendants.
- The
reattach()function is exactly the same asmove(). - Returns
dict[int, int]of{old index: new index, ...}for data and displayed rows separately and also anEventDataDict.
exists(item:str)->bool
item- a treeview iid.
parent(item:str)->str
item- a treeview iid.
index(item:str)->int
item- a treeview iid.
item_displayed(item:str)->bool
item- a treeview iid.
Make sure an items parents are all open, doesnot scroll to the item.
display_item(item:str,redraw:bool=False)->Sheet
item- a treeview iid.
- Make sure an items parents are all open and scrolls to the item.
scroll_to_item(item:str,redraw:bool=False)->Sheet
item- a treeview iid.
selection(cells:bool=False)->list[str]
Notes:
- Returns a list of selected iids (selected rows but as iids).
Parameters:
cellswhenTrueany selected cells will also qualify as selected items.
selection_set(*items,run_binding:bool=True,redraw:bool=True)->Sheet
- Sets selected rows (items).
selection_add(*items,run_binding:bool=True,redraw:bool=True)->Sheet
selection_remove(*items,redraw:bool=True)->Sheet
selection_toggle(*items,redraw:bool=True)->Sheet
Progress bars can be created for individual cells. They will only update when tkinter updates.
create_progress_bar(row:int,column:int,bg:str,fg:str,name:Hashable,percent:int=0,del_when_done:bool=False,)->Sheet
rowthe row coordinate to create the bar at.columnthe column coordinate to create the bar at.bgthe background color for the bar.fgthe text color for the bar.namea name is required for easy referral to the bar later on.- Names can be re-used for multiple bars.
percentthe starting progress of the bar as aninteither0,100or a number in between.del_when_doneifTruetheSheetwill automatically delete the progress bar once it is modified with a percent of100or more.
progress_bar(name:Hashable|None=None,cell:tuple[int,int]|None=None,percent:int|None=None,bg:str|None=None,fg:str|None=None,)->Sheet
Eithername orcell can be used to refer to existing progress bars:
namethe name given to a progress bar, or multiple progress bars.- If this parameter is used then
cellwill not be used. - Will modify all progress bars with the given name.
- If this parameter is used then
cell(tuple[int, int]) a tuple of twoints representing the progress bars location,(row, column).- Can only refer to one progress bar.
Values that can be modified:
bgthe background color for the bar, leave asNonefor no change.fgthe text color for the bar, leave asNonefor no change.percentthe progress of the bar as aninteither0,100or a number in between, leave asNonefor no change.
Note that this will delete the progress bars data from the Sheet as well.
del_progress_bar(name:Hashable|None=None,cell:tuple[int,int]|None=None,)->Sheet
Eithername orcell can be used to refer to existing progress bars:
namethe name given to a progress bar, or multiple progress bars.- Will delete all progress bars with the given name.
- If this parameter is used then
cellwill not be used.
cell(tuple[int, int]) a tuple of twoints representing the progress bars location,(row, column).- Can only refer to one progress bar.
Tags can be used to keep track of specific cells, rows and columns wherever they move. Note that:
- If rows/columns are deleted the the associated tags will be also.
- There is no equivalent
tag_bindfunctionality at this time. - All tagging functions use data indexes (not displayed indexes) - this is only relevant when there are hidden rows/columns.
tag_cell(cell:tuple[int,int],*tags,)->Sheet
Example:
sheet.tag_cell((0,0),"tag a1","tag a1 no.2")
tag_rows(rows:int|Iterator[int],*tags,)->Sheet
tag_columns(columns:int|Iterator[int],*tags,)->Sheet
tag(*key:CreateSpanTypes,tags:Iterator[str]|str="",)->Sheet
untag(cell:tuple[int,int]|None=None,rows:int|Iterator[int]|None=None,columns:int|Iterator[int]|None=None,)->Sheet
- This removes all tags from the cell, rows or columns provided.
tag_del(*tags,cells:bool=True,rows:bool=True,columns:bool=True,)->Sheet
- This deletes the provided tags from all
cellsifTrue,rowsifTrueandcolumnsifTrue.
tag_has(*tags,)->DotDict
Notes:
- Returns all cells, rows and columns associated withany of the provided tags in the form of a
dictwith dot notation accessbility which has the following keys:"cells"- with a value ofset[tuple[int, int]]where thetuples are cell coordinates -(row, column)."rows"- with a value ofset[int]where theints are rows."columns"- with a value ofset[int]where theints are columns.
- Returns data indexes.
- This functionupdates the
sets with any cells/rows/columns associated with each tag, it doesnot return cells/rows/columns that have all the provided tags.
Example:
sheet.tag_rows((0,1),"row tag a","row tag b")sheet.tag_rows(4,"row tag b")sheet.tag_rows(5,"row tag c")sheet.tag_rows(6,"row tag d")with_tags=sheet.tag_has("row tag b","row tag c")print (with_tags.rows)# prints {0, 1, 4, 5}
Usingpandas library, requires additional libraries:
pandasopenpyxl
fromtksheetimportSheetimporttkinterastkimportpandasaspdclassdemo(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 hereengine="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)
- Validating text editor input; in this demonstration the validation removes spaces from user input.
fromtksheetimportSheetimporttkinterastkclassdemo(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"forcinrange(50)]forrinrange(500)])self.sheet.enable_bindings("single_select","drag_select","edit_cell","paste","cut","copy","delete","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)self.sheet.edit_validation(self.validate_edits)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")defnew_right_click_button(self,event=None):print ("Hello World!")defbegin_edit_cell(self,event=None):returnevent.valuedefvalidate_edits(self,event):# remove spaces from any cell edits, including pasteifisinstance(event.value,str)andevent.value:returnevent.value.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().
fromtksheetimport (Sheet,num2alpha,)importtkinterastkclassdemo(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"forcinrange(50)]forrinrange(500)])self.sheet.enable_bindings("all","ctrl_select")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="nsw")defsheet_select_event(self,event=None):ifevent.eventname=="select"andevent.selection_boxesandevent.selected:# get the most recently selected box in case there are multiplebox=next(reversed(event.selection_boxes))type_=event.selection_boxes[box]iftype_=="cells":self.show_selections.config(text=f"{type_.capitalize()}:{box.from_r+1},{box.from_c+1} :{box.upto_r},{box.upto_c}")eliftype_=="rows":self.show_selections.config(text=f"{type_.capitalize()}:{box.from_r+1} :{box.upto_r}")eliftype_=="columns":self.show_selections.config(text=f"{type_.capitalize()}:{num2alpha(box.from_c)} :{num2alpha(box.upto_c-1)}")else: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).
fromtksheetimportSheetimporttkinterastkclassSheet_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)ifvalues:self.values(values)defvalues(self,values= []):self.set_sheet_data([[v]forvinvalues],reset_col_positions=False,reset_row_positions=False,redraw=False,verify=False)self.set_all_cell_sizes_to_text()classdemo(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} _________"foriinrange(2000)])self.listbox.grid(row=0,column=0,sticky="nswe")#self.listbox.values([f"new values {i}" for i in range(50)]) set valuesapp=demo()app.mainloop()
A very simple demonstration of row filtering using header dropdown boxes.
fromtksheetimport (Sheet,num2alphaasn2a,)importtkinterastkclassdemo(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,column_width=180,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.dropdown(self.sheet.span(n2a(0),header=True,table=False),values=["all","1","2","3"],set_value="all",selection_function=self.header_dropdown_selected,text="Header A Name", )self.sheet.dropdown(self.sheet.span(n2a(1),header=True,table=False),values=["all","a","b","c"],set_value="all",selection_function=self.header_dropdown_selected,text="Header B Name", )self.sheet.dropdown(self.sheet.span(n2a(2),header=True,table=False),values=["all","x","y","z"],set_value="all",selection_function=self.header_dropdown_selected,text="Header C Name", )defheader_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 eventhdrs[event.loc]=event.valueifall(dd=="all"forddinhdrs):self.sheet.display_rows("all")else:rows= [rnforrn,rowinenumerate(self.data)ifall(row[c]==eore=="all"forc,einenumerate(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.
fromtksheetimport (Sheet,num2alphaasn2a,)importtkinterastkclassdemo(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_horizontal=0,empty_vertical=0,paste_can_expand_x=True,paste_can_expand_y=True,align="w",header_align="c",data=[[f"Row{r}, Column{c}\nnewline 1\nnewline 2"forcinrange(6)]forrinrange(21)],headers=["Dropdown Column","Checkbox Column","Center Aligned Column","East Aligned Column","","", ],theme="dark",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_index_dropdown(r=0,values=["Dropdown"]+ [f"{i}"foriinrange(15)])self.sheet.create_index_checkbox(r=3,checked=True,text="Checkbox")self.sheet.create_dropdown(r="all",c=0,values=["Dropdown"]+ [f"{i}"foriinrange(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}"foriinrange(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")forrinrange(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.align(n2a(2),align="c")self.sheet.align(n2a(3),align="e")self.sheet.dropdown(self.sheet.span("A",header=True),values=["Dropdown"]+ [f"{i}"foriinrange(15)], )self.sheet.checkbox(self.sheet.span("B",header=True),checked=True,text="Checkbox", )self.sheet.align(5,0,align="c")self.sheet.highlight(5,0,bg="gray50",fg="blue")self.sheet.highlight(self.sheet.span(17,index=True,table=False),bg="yellow",fg="black", )self.sheet.highlight(12,1,bg="gray90",fg="purple")forrinrange(len(colors)):self.sheet.highlight(r,3,fg=colors[r])self.sheet.highlight(r,4,bg=colors[r],fg="black")self.sheet.highlight(r,5,bg=colors[r],fg="purple")self.sheet.highlight(self.sheet.span(n2a(5),header=True,table=False),bg="white",fg="purple", )self.sheet.set_all_column_widths()self.sheet.extra_bindings("all",self.all_extra_bindings)defhide_rows(self,event=None):rows=self.sheet.get_selected_rows()ifrows:self.sheet.hide_rows(rows)defshow_rows(self,event=None):self.sheet.display_rows("all",redraw=True)defhide_columns(self,event=None):columns=self.sheet.get_selected_columns()ifcolumns:self.sheet.hide_columns(columns)defshow_columns(self,event=None):self.sheet.display_columns("all",redraw=True)defall_extra_bindings(self,event=None):returnevent.valueapp=demo()app.mainloop()
To both load a csv file and save tksheet data as a csv file not including headers and index.
fromtksheetimportSheetimporttkinterastkfromtkinterimportfiledialogimportcsvfromos.pathimportnormpathimportioclassdemo(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}"forcinrange(6)]forrinrange(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")# create a span which encompasses the table, header and index# all data values, no displayed valuesself.sheet_span=self.sheet.span(header=True,index=True,hdisp=False,idisp=False, )# center the window and unhideself.update_idletasks()w=self.winfo_screenwidth()-20h=self.winfo_screenheight()-70size= (900,500)self.geometry("%dx%d+%d+%d"% (size+ ((w/2-size[0]/2),h/2-size[1]/2)))self.deiconify()defsave_sheet(self):filepath=filedialog.asksaveasfilename(parent=self,title="Save sheet as",filetypes=[("CSV File",".csv"), ("TSV File",".tsv")],defaultextension=".csv",confirmoverwrite=True, )ifnotfilepathornotfilepath.lower().endswith((".csv",".tsv")):returntry:withopen(normpath(filepath),"w",newline="",encoding="utf-8")asfh:writer=csv.writer(fh,dialect=csv.exceliffilepath.lower().endswith(".csv")elsecsv.excel_tab,lineterminator="\n", )writer.writerows(self.sheet_span.data)exceptExceptionaserror:print(error)returndefopen_csv(self):filepath=filedialog.askopenfilename(parent=self,title="Select a csv file")ifnotfilepathornotfilepath.lower().endswith((".csv",".tsv")):returntry:withopen(normpath(filepath),"r")asfilehandle:filedata=filehandle.read()self.sheet.reset()self.sheet_span.data= [rforrincsv.reader(io.StringIO(filedata),dialect=csv.Sniffer().sniff(filedata),skipinitialspace=False, ) ]exceptExceptionaserror:print(error)returnapp=demo()app.mainloop()
fromtksheetimport (Sheet,formatter,float_formatter,int_formatter,percentage_formatter,bool_formatter,truthy,falsy,num2alpha,)importtkinterastkfromdatetimeimportdatetime,datefromdateutilimportparser,tzfrommathimportceilimportredate_replace=re.compile("|".join(re.escape(char)forcharin"()[]<>"))# Custom formatter methodsdefround_up(x):try:# might not be a number if emptyreturnfloat(ceil(x))exceptException:returnxdefonly_numeric(s):return"".join(nforninf"{s}"ifn.isnumeric()orn==".")defconvert_to_local_datetime(dt:str,**kwargs):ifisinstance(dt,datetime):passelifisinstance(dt,date):dt=datetime(dt.year,dt.month,dt.day)else:ifisinstance(dt,str):dt=date_replace.sub("",dt)try:dt=parser.parse(dt)exceptException:raiseValueError(f"Could not parse{dt} as a datetime")ifdt.tzinfoisNone:dt.replace(tzinfo=tz.tzlocal())dt=dt.astimezone(tz.tzlocal())returndt.replace(tzinfo=None)defdatetime_to_string(dt:datetime,**kwargs):returndt.strftime("%d %b, %Y, %H:%M:%S")# Custom Formatter with additional kwargsdefcustom_datetime_to_str(dt:datetime,**kwargs):returndt.strftime(kwargs["format"])classdemo(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}"]*11forrinrange(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", ] )# num2alpha converts column integer to letter# Some examples of data formattingself.sheet[num2alpha(0)].format(float_formatter(nullable=False))self.sheet[num2alpha(1)].format(float_formatter())self.sheet[num2alpha(2)].format(int_formatter())self.sheet[num2alpha(3)].format(bool_formatter(truthy=truthy| {"nah yeah"},falsy=falsy| {"yeah nah"}))self.sheet[num2alpha(4)].format(percentage_formatter())# Custom Formatters# Custom using generic formatter interfaceself.sheet[num2alpha(5)].format(formatter(datatypes=datetime,format_function=convert_to_local_datetime,to_str_function=datetime_to_string,nullable=False,invalid_value="NaT", ) )# Custom formatself.sheet[num2alpha(6)].format(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_functionself.sheet[num2alpha(7)].format(float_formatter(post_format_function=round_up))self.sheet[num2alpha(8)].format(float_formatter(),pre_format_function=only_numeric)self.sheet[num2alpha(9)].dropdown(values=["","104%",0.24,"300%","not a number"],set_value=1,)self.sheet[num2alpha(9)].format(percentage_formatter(),decimals=0)self.sheet[num2alpha(10)].format(percentage_formatter(decimals=5))app=demo()app.mainloop()
Welcome and thank you for your interest intksheet!
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 licensehere.
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.
Please use theIssues 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.
With apologies, development of this library has ceased except for:
- Bug fixes.
- Behavioral issues.
- Documentation.
Pull requests for anything else are unlikely to be merged.
A special thank you to:
- @CalJaDav for the very helpful ideas/pull requests, guidance in implementing them and helping me become a better developer.
- @demberto for providing pull requests and guidance to modernize and improve the project.
- Allcontributors.
- Everyone who has reported an issue and helped me fix it.