Module ui.widgets.table
Customizations to tkintertable
Expand source code
# pylint: skip-file
"""
Customizations to tkintertable
"""
import math
from tkinter import END, StringVar, Menu
from tkinter.ttk import Entry, OptionMenu
from tkcalendar import DateEntry
from tkintertable import TableCanvas, Formula
from lib.repository.validator import is_valid_against
class EmpDatTableCanvas(TableCanvas):
"""
Override for TableCanvas
"""
def __init__(self, *args, col_modifiers: dict = None, on_change=None,
on_unsaved=None, on_selected=None, **kwargs):
"""
TableCanvas constructor
:param args: blanket passthrough
:param col_modifiers: dictionary modifying column entry
Example:
{
0: {
'read_only': True
},
1: {
'options': ['A', 'B', 'C"] # Options A, B, and C
},
2: {
'render_as': lambda X: Y # Render X as Y
}
}
:param on_change: callback called on every change
:param on_unsaved: callback called on every change, passes 1 parameter
on whether there are pending changes
:param on_selected: callback called on when a row is selected
:param kwargs: blanket passthrough
"""
super().__init__(*args, **kwargs)
self.col_modifiers = col_modifiers
self.unsaved = set()
self.on_change = on_change
self.on_unsaved = on_unsaved
self.on_selected = on_selected
def drawText(self, row, col, celltxt, fgcolor=None, align=None):
"""Draw the text inside a cell area"""
col_name = self.model.getColumnName(col)
if col_name in self.col_modifiers and 'render_as' in self.col_modifiers[col_name]:
celltxt = self.col_modifiers[col_name]['render_as'](celltxt)
if len(celltxt) == 0 or celltxt == 'None':
celltxt = ''
self.delete('celltext' + str(col) + '_' + str(row))
h = self.rowheight
x1, y1, x2, y2 = self.getCellCoords(row, col)
w = x2 - x1
wrap = False
pad = 5
# If celltxt is a number then we make it a string
if type(celltxt) is float or type(celltxt) is int:
celltxt = str(celltxt)
length = len(celltxt)
if length == 0:
return
# if cell width is less than x, print nothing
if w <= 10:
return
if fgcolor == None or fgcolor == "None":
fgcolor = 'black'
if align == None:
align = 'w'
if align == 'w':
x1 = x1 - w / 2 + pad
elif align == 'e':
x1 = x1 + w / 2 - pad
if w < 18:
celltxt = '.'
else:
fontsize = self.fontsize
colname = self.model.getColumnName(col)
# scaling between canvas and text normalised to about font 14
scale = 8.5 * float(fontsize) / 12
size = length * scale
if size > w:
newlength = w / scale
# print w, size, length, newlength
celltxt = celltxt[0:int(math.floor(newlength))]
# if celltxt is dict then we are drawing a hyperlink
if self.isLink(celltxt) == True:
haslink = 0
linktext = celltxt['text']
if len(linktext) > w / scale or w < 28:
linktext = linktext[0:int(w / fontsize * 1.2) - 2] + '..'
if celltxt['link'] != None and celltxt['link'] != '':
f, s = self.thefont
linkfont = (f, s, 'underline')
linkcolor = 'blue'
haslink = 1
else:
linkfont = self.thefont
linkcolor = fgcolor
rect = self.create_text(x1 + w / 2, y1 + h / 2,
text=linktext,
fill=linkcolor,
font=linkfont,
tag=('text', 'hlink', 'celltext' + str(col) + '_' + str(row)))
if haslink == 1:
self.tag_bind(rect, '<Double-Button-1>', self.check_hyperlink)
# just normal text
else:
rect = self.create_text(x1 + w / 2, y1 + h / 2,
text=celltxt,
fill=fgcolor,
font=self.thefont,
anchor=align,
tag=('text', 'celltext' + str(col) + '_' + str(row)))
return
def drawCellEntry(self, row, col, text=None):
"""When the user single/double clicks on a text/number cell, bring up entry window"""
col_name = self.model.getColumnName(col)
if self.read_only or (col_name in self.col_modifiers and
'read_only' in self.col_modifiers[col_name]
and self.col_modifiers[col_name]['read_only']):
return
# absrow = self.get_AbsoluteRow(row)
height = self.rowheight
model = self.getModel()
cellvalue = self.model.getCellRecord(row, col)
if Formula.isFormula(cellvalue):
return
else:
text = self.model.getValueAt(row, col)
if text == 'None':
text = ''
x1, y1, x2, y2 = self.getCellCoords(row, col)
w = x2 - x1
# Draw an entry window
txtvar = StringVar()
txtvar.set(text)
def callback(e):
value = txtvar.get()
if value == '=':
# do a dialog that gets the formula into a text area
# then they can click on the cells they want
# when done the user presses ok and its entered into the cell
self.cellentry.destroy()
# its all done here..
self.formula_Dialog(row, col)
return
coltype = self.model.getColumnType(col)
if coltype == 'number':
sta = self.checkDataEntry(e)
if sta == 1:
self.unsaved.add(self.model.getRecName(row))
model.setValueAt(value, row, col)
elif coltype == 'text':
self.unsaved.add(self.model.getRecName(row))
model.setValueAt(value, row, col)
color = self.model.getColorAt(row, col, 'fg')
self.drawText(row, col, value, color, align=self.align)
if not isinstance(e, str) and e.keysym == 'Return':
self.delete('entry')
# self.drawRect(row, col)
# self.gotonextCell(e)
if self.on_change:
self.on_change()
if len(self.unsaved) > 0:
self.on_unsaved(False, row, col)
else:
self.on_unsaved(True, row, col)
is_required = True if col_name in self.col_modifiers and \
'required' in self.col_modifiers[col_name] else False
if col_name in self.col_modifiers and 'validator' in self.col_modifiers[col_name]:
if not is_required and value == '':
self.model.setColorAt(row, col, 'white')
self.redrawCell(row, col)
return
if callable(self.col_modifiers[col_name]['validator']):
if not self.col_modifiers[col_name]['validator'](value):
self.model.setColorAt(row, col, 'coral')
self.redrawCell(row, col)
else:
if not is_valid_against(self.col_modifiers[col_name]['validator'], value):
self.model.setColorAt(row, col, 'coral')
self.redrawCell(row, col)
return
if col_name in self.col_modifiers and 'options' in self.col_modifiers[col_name]:
options = list(self.col_modifiers[col_name]['options'])
if cellvalue in options:
first = cellvalue
options.remove(first)
options.insert(0, first)
self.cellentry = OptionMenu(self.parentframe, txtvar, *options,
command=callback)
elif col_name in self.col_modifiers and 'date' in self.col_modifiers[col_name]:
self.cellentry = DateEntry(self.parentframe, width=20,
textvariable=txtvar,
takefocus=1,
font=self.thefont)
self.cellentry.bind('<<DateEntrySelected>>', callback)
else:
self.cellentry = Entry(self.parentframe, width=20,
textvariable=txtvar,
takefocus=1,
font=self.thefont)
self.cellentry.selection_range(0, END)
try:
self.cellentry.icursor(END)
except AttributeError:
pass
self.cellentry.bind('<Return>', callback)
self.cellentry.bind('<KeyRelease>', callback)
self.cellentry.focus_set()
self.entrywin = self.create_window(x1 + self.inset, y1 + self.inset,
width=w - self.inset * 2, height=height - self.inset * 2,
window=self.cellentry, anchor='nw',
tag='entry')
return
def handle_left_click(self, event):
"""Respond to a single press"""
self.on_selected()
super().handle_left_click(event)
def popupMenu(self, event, rows=None, cols=None, outside=None):
"""Add left and right click behaviour for canvas, should not have to override
this function, it will take its values from defined dicts in constructor"""
defaultactions = {"Set Fill Color": lambda: self.setcellColor(rows, cols, key='bg'),
"Set Text Color": lambda: self.setcellColor(rows, cols, key='fg'),
"Copy": lambda: self.copyCell(rows, cols),
"Paste": lambda: self.pasteCell(rows, cols),
"Fill Down": lambda: self.fillDown(rows, cols),
"Fill Right": lambda: self.fillAcross(cols, rows),
"Add Row(s)": lambda: self.addRows(),
"Delete Row(s)": lambda: self.deleteRow(),
"View Record": lambda: self.getRecordInfo(row),
"Clear Data": lambda: self.deleteCells(rows, cols),
"Select All": self.select_All,
"Auto Fit Columns": self.autoResizeColumns,
"Filter Records": self.showFilteringBar,
"New": self.new,
"Load": self.load,
"Save": self.save,
"Import text": self.importTable,
"Export csv": self.exportTable,
"Plot Selected": self.plotSelected,
"Plot Options": self.plotSetup,
"Export Table": self.exportTable,
"Preferences": self.showtablePrefs,
"Formulae->Value": lambda: self.convertFormulae(rows, cols)}
main = ["Set Fill Color", "Set Text Color", "Copy", "Paste", "Fill Down", "Fill Right",
"Clear Data"]
general = ["Select All", "Auto Fit Columns", "Filter Records", "Preferences"]
def createSubMenu(parent, label, commands):
menu = Menu(parent, tearoff=0)
popupmenu.add_cascade(label=label, menu=menu)
for action in commands:
menu.add_command(label=action, command=defaultactions[action])
return menu
def add_commands(fieldtype):
"""Add commands to popup menu for column type and specific cell"""
functions = self.columnactions[fieldtype]
for f in functions.keys():
func = getattr(self, functions[f])
popupmenu.add_command(label=f, command=lambda: func(row, col))
return
popupmenu = Menu(self, tearoff=0)
def popupFocusOut(event):
popupmenu.unpost()
if outside == None:
# if outside table, just show general items
row = self.get_row_clicked(event)
col = self.get_col_clicked(event)
coltype = self.model.getColumnType(col)
def add_defaultcommands():
"""now add general actions for all cells"""
for action in main:
if action == 'Fill Down' and (rows == None or len(rows) <= 1):
continue
if action == 'Fill Right' and (cols == None or len(cols) <= 1):
continue
else:
popupmenu.add_command(label=action, command=defaultactions[action])
return
if coltype in self.columnactions:
add_commands(coltype)
add_defaultcommands()
for action in general:
popupmenu.add_command(label=action, command=defaultactions[action])
popupmenu.add_separator()
# createSubMenu(popupmenu, 'File', filecommands)
# createSubMenu(popupmenu, 'Plot', plotcommands)
popupmenu.bind("<FocusOut>", popupFocusOut)
popupmenu.focus_set()
popupmenu.post(event.x_root, event.y_root)
return popupmenu
# def deleteRowByRecname(self, recname):
# """Delete a row"""
# row = self.get
# self.model.deleteRow(row)
# self.setSelectedRow(row-1)
# self.clearSelected()
# self.redrawTable()
Classes
class EmpDatTableCanvas (*args, col_modifiers: dict = None, on_change=None, on_unsaved=None, on_selected=None, **kwargs)
-
Override for TableCanvas
TableCanvas constructor :param args: blanket passthrough :param col_modifiers: dictionary modifying column entry Example: { 0: { 'read_only': True }, 1: { 'options': ['A', 'B', 'C"] # Options A, B, and C }, 2: { 'render_as': lambda X: Y # Render X as Y } } :param on_change: callback called on every change :param on_unsaved: callback called on every change, passes 1 parameter on whether there are pending changes :param on_selected: callback called on when a row is selected :param kwargs: blanket passthrough
Expand source code
class EmpDatTableCanvas(TableCanvas): """ Override for TableCanvas """ def __init__(self, *args, col_modifiers: dict = None, on_change=None, on_unsaved=None, on_selected=None, **kwargs): """ TableCanvas constructor :param args: blanket passthrough :param col_modifiers: dictionary modifying column entry Example: { 0: { 'read_only': True }, 1: { 'options': ['A', 'B', 'C"] # Options A, B, and C }, 2: { 'render_as': lambda X: Y # Render X as Y } } :param on_change: callback called on every change :param on_unsaved: callback called on every change, passes 1 parameter on whether there are pending changes :param on_selected: callback called on when a row is selected :param kwargs: blanket passthrough """ super().__init__(*args, **kwargs) self.col_modifiers = col_modifiers self.unsaved = set() self.on_change = on_change self.on_unsaved = on_unsaved self.on_selected = on_selected def drawText(self, row, col, celltxt, fgcolor=None, align=None): """Draw the text inside a cell area""" col_name = self.model.getColumnName(col) if col_name in self.col_modifiers and 'render_as' in self.col_modifiers[col_name]: celltxt = self.col_modifiers[col_name]['render_as'](celltxt) if len(celltxt) == 0 or celltxt == 'None': celltxt = '' self.delete('celltext' + str(col) + '_' + str(row)) h = self.rowheight x1, y1, x2, y2 = self.getCellCoords(row, col) w = x2 - x1 wrap = False pad = 5 # If celltxt is a number then we make it a string if type(celltxt) is float or type(celltxt) is int: celltxt = str(celltxt) length = len(celltxt) if length == 0: return # if cell width is less than x, print nothing if w <= 10: return if fgcolor == None or fgcolor == "None": fgcolor = 'black' if align == None: align = 'w' if align == 'w': x1 = x1 - w / 2 + pad elif align == 'e': x1 = x1 + w / 2 - pad if w < 18: celltxt = '.' else: fontsize = self.fontsize colname = self.model.getColumnName(col) # scaling between canvas and text normalised to about font 14 scale = 8.5 * float(fontsize) / 12 size = length * scale if size > w: newlength = w / scale # print w, size, length, newlength celltxt = celltxt[0:int(math.floor(newlength))] # if celltxt is dict then we are drawing a hyperlink if self.isLink(celltxt) == True: haslink = 0 linktext = celltxt['text'] if len(linktext) > w / scale or w < 28: linktext = linktext[0:int(w / fontsize * 1.2) - 2] + '..' if celltxt['link'] != None and celltxt['link'] != '': f, s = self.thefont linkfont = (f, s, 'underline') linkcolor = 'blue' haslink = 1 else: linkfont = self.thefont linkcolor = fgcolor rect = self.create_text(x1 + w / 2, y1 + h / 2, text=linktext, fill=linkcolor, font=linkfont, tag=('text', 'hlink', 'celltext' + str(col) + '_' + str(row))) if haslink == 1: self.tag_bind(rect, '<Double-Button-1>', self.check_hyperlink) # just normal text else: rect = self.create_text(x1 + w / 2, y1 + h / 2, text=celltxt, fill=fgcolor, font=self.thefont, anchor=align, tag=('text', 'celltext' + str(col) + '_' + str(row))) return def drawCellEntry(self, row, col, text=None): """When the user single/double clicks on a text/number cell, bring up entry window""" col_name = self.model.getColumnName(col) if self.read_only or (col_name in self.col_modifiers and 'read_only' in self.col_modifiers[col_name] and self.col_modifiers[col_name]['read_only']): return # absrow = self.get_AbsoluteRow(row) height = self.rowheight model = self.getModel() cellvalue = self.model.getCellRecord(row, col) if Formula.isFormula(cellvalue): return else: text = self.model.getValueAt(row, col) if text == 'None': text = '' x1, y1, x2, y2 = self.getCellCoords(row, col) w = x2 - x1 # Draw an entry window txtvar = StringVar() txtvar.set(text) def callback(e): value = txtvar.get() if value == '=': # do a dialog that gets the formula into a text area # then they can click on the cells they want # when done the user presses ok and its entered into the cell self.cellentry.destroy() # its all done here.. self.formula_Dialog(row, col) return coltype = self.model.getColumnType(col) if coltype == 'number': sta = self.checkDataEntry(e) if sta == 1: self.unsaved.add(self.model.getRecName(row)) model.setValueAt(value, row, col) elif coltype == 'text': self.unsaved.add(self.model.getRecName(row)) model.setValueAt(value, row, col) color = self.model.getColorAt(row, col, 'fg') self.drawText(row, col, value, color, align=self.align) if not isinstance(e, str) and e.keysym == 'Return': self.delete('entry') # self.drawRect(row, col) # self.gotonextCell(e) if self.on_change: self.on_change() if len(self.unsaved) > 0: self.on_unsaved(False, row, col) else: self.on_unsaved(True, row, col) is_required = True if col_name in self.col_modifiers and \ 'required' in self.col_modifiers[col_name] else False if col_name in self.col_modifiers and 'validator' in self.col_modifiers[col_name]: if not is_required and value == '': self.model.setColorAt(row, col, 'white') self.redrawCell(row, col) return if callable(self.col_modifiers[col_name]['validator']): if not self.col_modifiers[col_name]['validator'](value): self.model.setColorAt(row, col, 'coral') self.redrawCell(row, col) else: if not is_valid_against(self.col_modifiers[col_name]['validator'], value): self.model.setColorAt(row, col, 'coral') self.redrawCell(row, col) return if col_name in self.col_modifiers and 'options' in self.col_modifiers[col_name]: options = list(self.col_modifiers[col_name]['options']) if cellvalue in options: first = cellvalue options.remove(first) options.insert(0, first) self.cellentry = OptionMenu(self.parentframe, txtvar, *options, command=callback) elif col_name in self.col_modifiers and 'date' in self.col_modifiers[col_name]: self.cellentry = DateEntry(self.parentframe, width=20, textvariable=txtvar, takefocus=1, font=self.thefont) self.cellentry.bind('<<DateEntrySelected>>', callback) else: self.cellentry = Entry(self.parentframe, width=20, textvariable=txtvar, takefocus=1, font=self.thefont) self.cellentry.selection_range(0, END) try: self.cellentry.icursor(END) except AttributeError: pass self.cellentry.bind('<Return>', callback) self.cellentry.bind('<KeyRelease>', callback) self.cellentry.focus_set() self.entrywin = self.create_window(x1 + self.inset, y1 + self.inset, width=w - self.inset * 2, height=height - self.inset * 2, window=self.cellentry, anchor='nw', tag='entry') return def handle_left_click(self, event): """Respond to a single press""" self.on_selected() super().handle_left_click(event) def popupMenu(self, event, rows=None, cols=None, outside=None): """Add left and right click behaviour for canvas, should not have to override this function, it will take its values from defined dicts in constructor""" defaultactions = {"Set Fill Color": lambda: self.setcellColor(rows, cols, key='bg'), "Set Text Color": lambda: self.setcellColor(rows, cols, key='fg'), "Copy": lambda: self.copyCell(rows, cols), "Paste": lambda: self.pasteCell(rows, cols), "Fill Down": lambda: self.fillDown(rows, cols), "Fill Right": lambda: self.fillAcross(cols, rows), "Add Row(s)": lambda: self.addRows(), "Delete Row(s)": lambda: self.deleteRow(), "View Record": lambda: self.getRecordInfo(row), "Clear Data": lambda: self.deleteCells(rows, cols), "Select All": self.select_All, "Auto Fit Columns": self.autoResizeColumns, "Filter Records": self.showFilteringBar, "New": self.new, "Load": self.load, "Save": self.save, "Import text": self.importTable, "Export csv": self.exportTable, "Plot Selected": self.plotSelected, "Plot Options": self.plotSetup, "Export Table": self.exportTable, "Preferences": self.showtablePrefs, "Formulae->Value": lambda: self.convertFormulae(rows, cols)} main = ["Set Fill Color", "Set Text Color", "Copy", "Paste", "Fill Down", "Fill Right", "Clear Data"] general = ["Select All", "Auto Fit Columns", "Filter Records", "Preferences"] def createSubMenu(parent, label, commands): menu = Menu(parent, tearoff=0) popupmenu.add_cascade(label=label, menu=menu) for action in commands: menu.add_command(label=action, command=defaultactions[action]) return menu def add_commands(fieldtype): """Add commands to popup menu for column type and specific cell""" functions = self.columnactions[fieldtype] for f in functions.keys(): func = getattr(self, functions[f]) popupmenu.add_command(label=f, command=lambda: func(row, col)) return popupmenu = Menu(self, tearoff=0) def popupFocusOut(event): popupmenu.unpost() if outside == None: # if outside table, just show general items row = self.get_row_clicked(event) col = self.get_col_clicked(event) coltype = self.model.getColumnType(col) def add_defaultcommands(): """now add general actions for all cells""" for action in main: if action == 'Fill Down' and (rows == None or len(rows) <= 1): continue if action == 'Fill Right' and (cols == None or len(cols) <= 1): continue else: popupmenu.add_command(label=action, command=defaultactions[action]) return if coltype in self.columnactions: add_commands(coltype) add_defaultcommands() for action in general: popupmenu.add_command(label=action, command=defaultactions[action]) popupmenu.add_separator() # createSubMenu(popupmenu, 'File', filecommands) # createSubMenu(popupmenu, 'Plot', plotcommands) popupmenu.bind("<FocusOut>", popupFocusOut) popupmenu.focus_set() popupmenu.post(event.x_root, event.y_root) return popupmenu
Ancestors
- tkintertable.Tables.TableCanvas
- tkinter.Canvas
- tkinter.Widget
- tkinter.BaseWidget
- tkinter.Misc
- tkinter.Pack
- tkinter.Place
- tkinter.Grid
- tkinter.XView
- tkinter.YView
Methods
def drawCellEntry(self, row, col, text=None)
-
When the user single/double clicks on a text/number cell, bring up entry window
Expand source code
def drawCellEntry(self, row, col, text=None): """When the user single/double clicks on a text/number cell, bring up entry window""" col_name = self.model.getColumnName(col) if self.read_only or (col_name in self.col_modifiers and 'read_only' in self.col_modifiers[col_name] and self.col_modifiers[col_name]['read_only']): return # absrow = self.get_AbsoluteRow(row) height = self.rowheight model = self.getModel() cellvalue = self.model.getCellRecord(row, col) if Formula.isFormula(cellvalue): return else: text = self.model.getValueAt(row, col) if text == 'None': text = '' x1, y1, x2, y2 = self.getCellCoords(row, col) w = x2 - x1 # Draw an entry window txtvar = StringVar() txtvar.set(text) def callback(e): value = txtvar.get() if value == '=': # do a dialog that gets the formula into a text area # then they can click on the cells they want # when done the user presses ok and its entered into the cell self.cellentry.destroy() # its all done here.. self.formula_Dialog(row, col) return coltype = self.model.getColumnType(col) if coltype == 'number': sta = self.checkDataEntry(e) if sta == 1: self.unsaved.add(self.model.getRecName(row)) model.setValueAt(value, row, col) elif coltype == 'text': self.unsaved.add(self.model.getRecName(row)) model.setValueAt(value, row, col) color = self.model.getColorAt(row, col, 'fg') self.drawText(row, col, value, color, align=self.align) if not isinstance(e, str) and e.keysym == 'Return': self.delete('entry') # self.drawRect(row, col) # self.gotonextCell(e) if self.on_change: self.on_change() if len(self.unsaved) > 0: self.on_unsaved(False, row, col) else: self.on_unsaved(True, row, col) is_required = True if col_name in self.col_modifiers and \ 'required' in self.col_modifiers[col_name] else False if col_name in self.col_modifiers and 'validator' in self.col_modifiers[col_name]: if not is_required and value == '': self.model.setColorAt(row, col, 'white') self.redrawCell(row, col) return if callable(self.col_modifiers[col_name]['validator']): if not self.col_modifiers[col_name]['validator'](value): self.model.setColorAt(row, col, 'coral') self.redrawCell(row, col) else: if not is_valid_against(self.col_modifiers[col_name]['validator'], value): self.model.setColorAt(row, col, 'coral') self.redrawCell(row, col) return if col_name in self.col_modifiers and 'options' in self.col_modifiers[col_name]: options = list(self.col_modifiers[col_name]['options']) if cellvalue in options: first = cellvalue options.remove(first) options.insert(0, first) self.cellentry = OptionMenu(self.parentframe, txtvar, *options, command=callback) elif col_name in self.col_modifiers and 'date' in self.col_modifiers[col_name]: self.cellentry = DateEntry(self.parentframe, width=20, textvariable=txtvar, takefocus=1, font=self.thefont) self.cellentry.bind('<<DateEntrySelected>>', callback) else: self.cellentry = Entry(self.parentframe, width=20, textvariable=txtvar, takefocus=1, font=self.thefont) self.cellentry.selection_range(0, END) try: self.cellentry.icursor(END) except AttributeError: pass self.cellentry.bind('<Return>', callback) self.cellentry.bind('<KeyRelease>', callback) self.cellentry.focus_set() self.entrywin = self.create_window(x1 + self.inset, y1 + self.inset, width=w - self.inset * 2, height=height - self.inset * 2, window=self.cellentry, anchor='nw', tag='entry') return
def drawText(self, row, col, celltxt, fgcolor=None, align=None)
-
Draw the text inside a cell area
Expand source code
def drawText(self, row, col, celltxt, fgcolor=None, align=None): """Draw the text inside a cell area""" col_name = self.model.getColumnName(col) if col_name in self.col_modifiers and 'render_as' in self.col_modifiers[col_name]: celltxt = self.col_modifiers[col_name]['render_as'](celltxt) if len(celltxt) == 0 or celltxt == 'None': celltxt = '' self.delete('celltext' + str(col) + '_' + str(row)) h = self.rowheight x1, y1, x2, y2 = self.getCellCoords(row, col) w = x2 - x1 wrap = False pad = 5 # If celltxt is a number then we make it a string if type(celltxt) is float or type(celltxt) is int: celltxt = str(celltxt) length = len(celltxt) if length == 0: return # if cell width is less than x, print nothing if w <= 10: return if fgcolor == None or fgcolor == "None": fgcolor = 'black' if align == None: align = 'w' if align == 'w': x1 = x1 - w / 2 + pad elif align == 'e': x1 = x1 + w / 2 - pad if w < 18: celltxt = '.' else: fontsize = self.fontsize colname = self.model.getColumnName(col) # scaling between canvas and text normalised to about font 14 scale = 8.5 * float(fontsize) / 12 size = length * scale if size > w: newlength = w / scale # print w, size, length, newlength celltxt = celltxt[0:int(math.floor(newlength))] # if celltxt is dict then we are drawing a hyperlink if self.isLink(celltxt) == True: haslink = 0 linktext = celltxt['text'] if len(linktext) > w / scale or w < 28: linktext = linktext[0:int(w / fontsize * 1.2) - 2] + '..' if celltxt['link'] != None and celltxt['link'] != '': f, s = self.thefont linkfont = (f, s, 'underline') linkcolor = 'blue' haslink = 1 else: linkfont = self.thefont linkcolor = fgcolor rect = self.create_text(x1 + w / 2, y1 + h / 2, text=linktext, fill=linkcolor, font=linkfont, tag=('text', 'hlink', 'celltext' + str(col) + '_' + str(row))) if haslink == 1: self.tag_bind(rect, '<Double-Button-1>', self.check_hyperlink) # just normal text else: rect = self.create_text(x1 + w / 2, y1 + h / 2, text=celltxt, fill=fgcolor, font=self.thefont, anchor=align, tag=('text', 'celltext' + str(col) + '_' + str(row))) return
def handle_left_click(self, event)
-
Respond to a single press
Expand source code
def handle_left_click(self, event): """Respond to a single press""" self.on_selected() super().handle_left_click(event)
def popupMenu(self, event, rows=None, cols=None, outside=None)
-
Add left and right click behaviour for canvas, should not have to override this function, it will take its values from defined dicts in constructor
Expand source code
def popupMenu(self, event, rows=None, cols=None, outside=None): """Add left and right click behaviour for canvas, should not have to override this function, it will take its values from defined dicts in constructor""" defaultactions = {"Set Fill Color": lambda: self.setcellColor(rows, cols, key='bg'), "Set Text Color": lambda: self.setcellColor(rows, cols, key='fg'), "Copy": lambda: self.copyCell(rows, cols), "Paste": lambda: self.pasteCell(rows, cols), "Fill Down": lambda: self.fillDown(rows, cols), "Fill Right": lambda: self.fillAcross(cols, rows), "Add Row(s)": lambda: self.addRows(), "Delete Row(s)": lambda: self.deleteRow(), "View Record": lambda: self.getRecordInfo(row), "Clear Data": lambda: self.deleteCells(rows, cols), "Select All": self.select_All, "Auto Fit Columns": self.autoResizeColumns, "Filter Records": self.showFilteringBar, "New": self.new, "Load": self.load, "Save": self.save, "Import text": self.importTable, "Export csv": self.exportTable, "Plot Selected": self.plotSelected, "Plot Options": self.plotSetup, "Export Table": self.exportTable, "Preferences": self.showtablePrefs, "Formulae->Value": lambda: self.convertFormulae(rows, cols)} main = ["Set Fill Color", "Set Text Color", "Copy", "Paste", "Fill Down", "Fill Right", "Clear Data"] general = ["Select All", "Auto Fit Columns", "Filter Records", "Preferences"] def createSubMenu(parent, label, commands): menu = Menu(parent, tearoff=0) popupmenu.add_cascade(label=label, menu=menu) for action in commands: menu.add_command(label=action, command=defaultactions[action]) return menu def add_commands(fieldtype): """Add commands to popup menu for column type and specific cell""" functions = self.columnactions[fieldtype] for f in functions.keys(): func = getattr(self, functions[f]) popupmenu.add_command(label=f, command=lambda: func(row, col)) return popupmenu = Menu(self, tearoff=0) def popupFocusOut(event): popupmenu.unpost() if outside == None: # if outside table, just show general items row = self.get_row_clicked(event) col = self.get_col_clicked(event) coltype = self.model.getColumnType(col) def add_defaultcommands(): """now add general actions for all cells""" for action in main: if action == 'Fill Down' and (rows == None or len(rows) <= 1): continue if action == 'Fill Right' and (cols == None or len(cols) <= 1): continue else: popupmenu.add_command(label=action, command=defaultactions[action]) return if coltype in self.columnactions: add_commands(coltype) add_defaultcommands() for action in general: popupmenu.add_command(label=action, command=defaultactions[action]) popupmenu.add_separator() # createSubMenu(popupmenu, 'File', filecommands) # createSubMenu(popupmenu, 'Plot', plotcommands) popupmenu.bind("<FocusOut>", popupFocusOut) popupmenu.focus_set() popupmenu.post(event.x_root, event.y_root) return popupmenu