# Author: Miguel Martinez Lopez try: from tkinter import * except ImportError: from Tkinter import * class Cell(Frame): """Base class for cells""" class Data_Cell(Cell): def __init__(self, master, width, variable, anchor=W, bordercolor=None, padx=0, pady=0, background=None, foreground=None, font=None): Cell.__init__(self, master, width=width, background=background, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=1, bd= 0) self._message_widget = Message(self, width=width, textvariable=variable, font=font, background=background, foreground=foreground) self._message_widget.pack(expand=True, padx=padx, pady=pady, anchor=anchor) class Header_Cell(Cell): def __init__(self, master, text, bordercolor=None, padx=None, pady=None, background=None, foreground=None, font=None): Cell.__init__(self, master, background=background, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=1, bd= 0) self._header_label = Label(self, text=text, background=background, foreground=foreground, font=font) self._header_label.pack(padx=padx, pady=pady, expand=True) if bordercolor is not None: separator = Frame(self, height=2, background=bordercolor, bd=0, highlightthickness=0, class_="Separator") separator.pack(fill=X) class Table(Frame): def __init__(self, master, columns, column_widths, minwidth=20,minheight=20, padx=5, pady=5, cell_font=None, cell_foreground="black", cell_background="white", header_font=None, header_background="white", header_foreground="black", bordercolor = "#999999", stripped_rows=("#EEEEEE", "white"), cell_anchor=W): Frame.__init__(self,master, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=1, bd= 0) self._cell_background = cell_background self._cell_foreground = cell_foreground self._cell_font = cell_font self._cell_anchor = cell_anchor self._stripped_rows = stripped_rows self._padx = padx self._pady = pady self._bordercolor = bordercolor self._data_vars = [] self._columns = columns self._column_widths = column_widths for j in range(len(columns)): column_name = columns[j] column_width = column_widths[j] header_cell = Header_Cell(self, text=column_name, font=header_font, background=header_background, foreground=header_foreground, padx=padx, pady=pady, bordercolor=bordercolor) header_cell.grid(row=0, column=j, sticky=N+E+W+S) def _add_rows(self, n): number_of_rows = self.number_of_rows for i in range(number_of_rows+1, number_of_rows+n+1): list_of_vars = [] for j in range(self.number_of_columns): var = StringVar() list_of_vars.append(var) width = self._column_widths[j] if self._stripped_rows: cell = Data_Cell(self, width, variable=var, bordercolor=self._bordercolor, padx=self._padx, pady=self._pady, background=self._stripped_rows[(i+1)%2], foreground=self._cell_foreground, font=self._cell_font, anchor=self._cell_anchor) else: cell = Data_Cell(self, width, variable=var, bordercolor=self._bordercolor, padx=self._padx, pady=self._pady, background=self._cell_background, foreground=self._cell_foreground, font=self._cell_font, anchor=self._cell_anchor) cell.grid(row=i, column=j, sticky=N+E+W+S) self._data_vars.append(list_of_vars) def _delete_rows(self, n): number_of_rows = self.number_of_rows for i in range(number_of_rows-n+1, number_of_rows+1): for j in range(self.number_of_columns): self.grid_slaves(row=i, column=j)[0].destroy() def set_data(self, data): n = len(data) m = len(data[0]) number_of_rows = self.number_of_rows if number_of_rows > n: self._delete_rows(number_of_rows-n) elif number_of_rows < n: self._add_rows(n-number_of_rows) for i in range(n): for j in range(m): self._data_vars[i][j].set(data[i][j]) def get_data(self): number_of_rows = self.number_of_rows number_of_columns = self.number_of_columns data = [] for i in range(number_of_rows): row = [] row_of_vars = self._data_vars[i] for j in range(number_of_columns): cell_data = row_of_vars[j].get() row.append(cell_data) data.append(row) return data @property def number_of_rows(self): return len(self._data_vars) @property def number_of_columns(self): return len(self._columns) def row(self, index, data=None): if data is None: row = [] row_of_vars = self._data_vars[index] for j in range(self.number_of_columns): row.append(row_of_vars[j].get()) return row else: number_of_columns = self.number_of_columns if len(data) != number_of_columns: raise ValueError("data has no %d elements: %s"%(number_of_columns, data)) row_of_vars = self._data_vars[index] for j in range(number_of_columns): row_of_vars[index][j].set(data[j]) def column(self, index, data=None): if data is None: column= [] for i in range(self.number_of_rows): column.append(self._data_vars[i][index].get()) return column else: number_of_rows = self.number_of_rows if len(data) != number_of_rows: raise ValueError("data has no %d elements: %s"%(number_of_rows, data)) for i in range(number_of_columns): self._data_vars[i][index].set(data[i]) def clear(self): for i in range(self.number_of_rows): for j in range(self.number_of_columns): self._data_vars[row][column].set("") def delete_row(self, index): column_indices = range(0, number_of_columns) for i in range(index, self.number_of_rows-1): row_of_vars_1 = self._data_vars[i] row_of_vars_2 = self._data_vars[i+1] for j in column_indices: row_of_vars_1[j].set(row_of_vars_2[j]) self._delete_rows(1) def insert_row(self, data, index=END): column_indices = range(0, number_of_columns) if index == END: index = self.number_of_rows - 1 self._add_rows(1) for i in range(self.number_of_rows-1, index-1, -1): row_of_vars_1 = self._data_vars[i-1] row_of_vars_2 = self._data_vars[i] for j in column_indices: row_of_vars_2[j].set(row_of_vars_1[j]) row_of_vars = self._data_vars[index] for j in row_of_vars: row_of_vars[j].set(data[j].get()) def cell(self, row, column, data=None): """Get the value of a table cell""" if data is None: self._data_vars[row][column].get() else: self._data_vars[row][column].set(data) def __getitem__(self, index): if isinstance(index, tuple): row, column = index return self.cell(row, column) else: raise Exception("Row and column indices are required") def __setitem__(self, index, value): if isinstance(index, tuple): row, column = index self.cell(row, column, value) else: raise Exception("Row and column indices are required") root = Tk() table = Table(root, ["columna A", "columna B", "columna C"], [100, 200, 100]) table.pack(padx=10,pady=10) table.set_data([[1,2,3],[4,5,6], [7,8,9], [10,11,12]]) table.cell(0,0, " a fdas fasd fasdf asdf asdfasdf asdf asdfa sdfas asd sadf ") root.mainloop()