Welcome, guest | Sign In | My Account | Store | Cart
# 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()

History