Welcome, guest | Sign In | My Account | Store | Cart
# Author: Miguel Martinez Lopez
# Version: 0.17

try:
    from Tkinter import Frame, Label, Message, StringVar, Canvas
    from ttk import Scrollbar
    from Tkconstants import *
except ImportError:
    from tkinter import Frame, Label, Message, StringVar, Canvas
    from tkinter.ttk import Scrollbar
    from tkinter.constants import *

import platform

OS = platform.system()

def make_mouse_wheel_handler(widget, orient, factor = 1, what="units"):
    view_command = getattr(widget, orient+'view')
    
    if OS == 'Linux':
        def onMouseWheel(event):
            if event.num == 4:
                view_command("scroll",(-1)*factor, what)
            elif event.num == 5:
                view_command("scroll",factor, what) 
            
    elif OS == 'Windows':
        def onMouseWheel(event):        
            view_command("scroll",(-1)*int((event.delta/120)*factor), what) 
    
    elif OS == 'Darwin':
        def onMouseWheel(event):        
            view_command("scroll",event.delta, what)
    
    return onMouseWheel

class Mousewheel_Support(object):    

    # implemetnation of singleton pattern
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = object.__new__(cls)
        return cls._instance

    def __init__(self, root, horizontal_factor = 2, vertical_factor=2):
        
        self._active_area = None
        
        if isinstance(horizontal_factor, int):
            self.horizontal_factor = horizontal_factor
        else:
            raise Exception("Vertical factor must be an integer.")

        if isinstance(vertical_factor, int):
            self.vertical_factor = vertical_factor
        else:
            raise Exception("Horizontal factor must be an integer.")

        if OS == "Linux" :
            root.bind_all('<4>', self._on_mouse_wheel,  add='+')
            root.bind_all('<5>', self._on_mouse_wheel,  add='+')
        else:
            # Windows and MacOS
            root.bind_all("<MouseWheel>", self._on_mouse_wheel,  add='+')

    def _on_mouse_wheel(self,event):
        if self._active_area:
            self._active_area.onMouseWheel(event)

    def _on_mouse_enter_scrolling_area(self, widget):
        self._active_area = widget

    def _on_mouse_leave_scrolling_area(self):
        self._active_area = None

    def add_support_to(self, widget=None, xscrollbar=None, yscrollbar=None, what="units", horizontal_factor=None, vertical_factor=None):
        if xscrollbar is not None and not hasattr(xscrollbar, 'onMouseWheel'):
            horizontal_factor = horizontal_factor or self.horizontal_factor

            xscrollbar.onMouseWheel = make_mouse_wheel_handler(widget,'x', self.horizontal_factor, what)
            xscrollbar.bind('<Enter>', lambda event, scrollbar=xscrollbar: self._on_mouse_enter_scrolling_area(scrollbar) )
            xscrollbar.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())

        if yscrollbar is not None and not hasattr(yscrollbar, 'onMouseWheel'):
            vertical_factor = vertical_factor or self.vertical_factor

            yscrollbar.onMouseWheel = make_mouse_wheel_handler(widget,'y', self.vertical_factor, what)
            yscrollbar.bind('<Enter>', lambda event, scrollbar=yscrollbar: self._on_mouse_enter_scrolling_area(scrollbar) )
            yscrollbar.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())

        main_scrollbar = yscrollbar if yscrollbar is not None else xscrollbar
        
        if widget is not None and main_scrollbar is not None:
            widget.bind('<Enter>',lambda event: self._on_mouse_enter_scrolling_area(widget))
            widget.bind('<Leave>', lambda event: self._on_mouse_leave_scrolling_area())

            widget.onMouseWheel = main_scrollbar.onMouseWheel

class Scrolling_Area(Frame, object):

    def __init__(self, master, width=None, height=None, mousewheel_speed = 2, scroll_horizontally=True, xscrollbar=None, scroll_vertically=True, yscrollbar=None, outer_background=None, inner_frame=Frame, window_minwidth=None, window_minheight = None, **kw):
        Frame.__init__(self, master, class_=self.__class__)

        if outer_background:
            self.configure(background=outer_background)

        self._width = width
        self._height = height

        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(0, weight=1)

        self.canvas = Canvas(self, background=outer_background, highlightthickness=0, width=width, height=height)
        self.canvas.grid(row=0, column=0, sticky=N+E+W+S)

        self._window_minwidth = window_minwidth
        self._window_minheight = window_minheight

        if scroll_vertically:
            if yscrollbar is not None:
                self.yscrollbar = yscrollbar
            else:
                self.yscrollbar = Scrollbar(self, orient=VERTICAL)
                self.yscrollbar.grid(row=0, column=1,sticky=N+S)
        
            self.canvas.configure(yscrollcommand=self.yscrollbar.set)
            self.yscrollbar['command']=self.canvas.yview
        else:
            self.yscrollbar = None

        if scroll_horizontally:
            if xscrollbar is not None:
                self.xscrollbar = xscrollbar
            else:
                self.xscrollbar = Scrollbar(self, orient=HORIZONTAL)
                self.xscrollbar.grid(row=1, column=0, sticky=E+W)
            
            self.canvas.configure(xscrollcommand=self.xscrollbar.set)
            self.xscrollbar['command']=self.canvas.xview
        else:
            self.xscrollbar = None

        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)

        self.innerFrame= inner_frame(self.canvas, **kw)
        self.innerFrame.pack()
        
        self.canvas.create_window(0, 0, window=self.innerFrame, anchor='nw', tags="inner_frame")

        self.canvas.bind('<Configure>', self._on_configure)

        Mousewheel_Support(self).add_support_to(self.canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar)

    @property
    def width(self):
        return self._width
        
    @property
    def window_minwidth(self):
        return self._window_minwidth
        
    @window_minwidth.setter
    def window_minwidth(self, window_minwidth):
        self._window_minwidth = window_minwidth

    @property
    def window_minheight(self):
        return self._window_minheight
        
    @window_minheight.setter
    def window_minheight(self, window_minheight):
        self._window_minheight = window_minheight

    @width.setter
    def width(self, width):
        self._width = width
        self.canvas.configure(width= width)

    @property
    def height(self):
        return self._height
        
    @height.setter
    def height(self, height):
        self._height = height
        self.canvas.configure(height = height)

    def _on_configure(self, event):
        if self._window_minwidth is not None:
            width = max(event.width, self._window_minwidth)
        else:
            width = max(self.innerFrame.winfo_reqwidth(), event.width)
            
        if self._window_minheight is not None:
            height = max(event.height, self._window_minheight)
        else:
            height = max(self.innerFrame.winfo_reqheight(), event.height)


        self.update_viewport(width, height)

    def update_viewport(self, width, height):
        self.canvas.configure(scrollregion="0 0 %s %s" % (width, height))
        self.canvas.itemconfigure("inner_frame", width=width, height=height)

class Cell(Frame):
    """Base class for cells"""

class Data_Cell(Cell):
    def __init__(self, master, variable, anchor=W, bordercolor=None, borderwidth=1, padx=0, pady=0, background=None, foreground=None, font=None):
        Cell.__init__(self, master, background=background, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=borderwidth, bd= 0)

        self._message_widget = Message(self, 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, borderwidth=1, padx=0, pady=0, background=None, foreground=None, font=None, anchor=CENTER, separator=True):
        Cell.__init__(self, master, background=background, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=borderwidth, bd= 0)
        self.pack_propagate(False)

        self._header_label = Label(self, text=text, background=background, foreground=foreground, font=font)
        self._header_label.pack(padx=padx, pady=pady, expand=True)

        if separator and bordercolor is not None:
            separator = Frame(self, height=2, background=bordercolor, bd=0, highlightthickness=0, class_="Separator")
            separator.pack(fill=X, anchor=anchor)

        self.update()
        height = self._header_label.winfo_reqheight() + 2*padx
        width = self._header_label.winfo_reqwidth() + 2*pady

        self.configure(height=height, width=width)
        
class Table(Frame):
    def __init__(self, master, columns, column_weights=None, column_minwidths=None, height=None, minwidth=20, minheight=20, padx=5, pady=5, cell_font=None, cell_foreground="black", cell_background="white", cell_anchor=W, header_font=None, header_background="white", header_foreground="black", header_anchor=CENTER, bordercolor = "#999999", innerborder=True, outerborder=True, stripped_rows=("#EEEEEE", "white"), on_change_data=None, mousewheel_speed = 2, scroll_horizontally=False, scroll_vertically=True):
        outerborder_width = 1 if outerborder else 0

        Frame.__init__(self,master, 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._innerborder_width = 1 if innerborder else 0

        self._data_vars = []

        self._columns = columns
        
        self._number_of_rows = 0
        self._number_of_columns = len(columns)

        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(1, weight=1)
        
        self._head = Frame(self, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=outerborder_width, bd= 0)
        self._head.grid(row=0, column=0, sticky=E+W)

        header_separator = False if outerborder else True

        for j in range(len(columns)):
            column_name = columns[j]

            header_cell = Header_Cell(self._head, text=column_name, borderwidth=self._innerborder_width, font=header_font, background=header_background, foreground=header_foreground, padx=padx, pady=pady, bordercolor=bordercolor, anchor=header_anchor, separator=header_separator)
            header_cell.grid(row=0, column=j, sticky=N+E+W+S)

        if scroll_horizontally or scroll_vertically:
            if scroll_horizontally:
                xscrollbar = Scrollbar(self, orient=HORIZONTAL)
                xscrollbar.grid(row=2, column=0, sticky=E+W)
            else:
                xscrollbar = None

            if scroll_vertically:
                yscrollbar = Scrollbar(self, orient=VERTICAL)
                yscrollbar.grid(row=1, column=1, sticky=N+S)
            else:
                yscrollbar = None

            scrolling_area = Scrolling_Area(self, width=self._head.winfo_reqwidth(), height=height, scroll_horizontally=scroll_horizontally, xscrollbar=xscrollbar, scroll_vertically=scroll_vertically, yscrollbar=yscrollbar)
            scrolling_area.grid(row=1, column=0, sticky=N+E+W+S)

            self._body = Frame(scrolling_area.innerFrame, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=outerborder_width, bd= 0)
            self._body.pack()
            
            _on_change_data = on_change_data
            def on_change_data():
                self.update()
                width = self._body.winfo_reqwidth()

                scrolling_area.update_viewport(width=width, height=self._body.winfo_reqheight())
                
                if _on_change_data is not None:
                    _on_change_data()
        else:
            self._body = Frame(self, height=height, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=outerborder_width, bd= 0)
            self._body.grid(row=1, column=0, sticky=N+E+W+S)

        if column_weights is None:
            for j in range(len(columns)):
                self._body.grid_columnconfigure(j, weight=1)
        else:
            for j, weight in enumerate(column_weights):
                self._body.grid_columnconfigure(j, weight=weight)

        if column_minwidths is not None:
            
            for j, minwidth in enumerate(column_minwidths):
                if minwidth is None:
                    header_cell = self._head.grid_slaves(row=0, column=j)[0]
                    minwidth = header_cell.winfo_reqwidth()

                self._body.grid_columnconfigure(j, minsize=minwidth)
        else:
            for j in range(len(columns)):
                header_cell = self._head.grid_slaves(row=0, column=j)[0]
                minwidth = header_cell.winfo_reqwidth()

                self._body.grid_columnconfigure(j, minsize=minwidth)

        self._on_change_data = on_change_data

    def _append_n_rows(self, n):
        number_of_rows = self._number_of_rows
        number_of_columns = self._number_of_columns

        for i in range(number_of_rows, number_of_rows+n):
            list_of_vars = []
            for j in range(number_of_columns):
                var = StringVar()
                list_of_vars.append(var)

                if self._stripped_rows:
                    cell = Data_Cell(self._body, borderwidth=self._innerborder_width, variable=var, bordercolor=self._bordercolor, padx=self._padx, pady=self._pady, background=self._stripped_rows[i%2], foreground=self._cell_foreground, font=self._cell_font, anchor=self._cell_anchor)
                else:
                    cell = Data_Cell(self._body, borderwidth=self._innerborder_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)
            
        if number_of_rows == 0:
            for j in range(self.number_of_columns):
                header_cell = self._head.grid_slaves(row=0, column=j)[0]
                data_cell = self._body.grid_slaves(row=0, column=j)[0]
                data_cell.bind("<Configure>", lambda event, header_cell=header_cell: header_cell.configure(width=event.width), add="+")

        self._number_of_rows += n

    def _pop_n_rows(self, n):
        number_of_rows = self._number_of_rows
        number_of_columns = self._number_of_columns
        
        for i in range(number_of_rows-n, number_of_rows):
            for j in range(number_of_columns):
                self._body.grid_slaves(row=i, column=j)[0].destroy()
            
            self._data_vars.pop()
    
        self._number_of_rows -= n

    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._pop_n_rows(number_of_rows-n)
        elif number_of_rows < n:
            self._append_n_rows(n-number_of_rows)

        for i in range(n):
            for j in range(m):
                self._data_vars[i][j].set(data[i][j])

        if self._on_change_data is not None: self._on_change_data()

    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 self._number_of_rows

    @property
    def number_of_columns(self):
        return self._number_of_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])
                
            if self._on_change_data is not None: self._on_change_data()

    def column(self, index, data=None):
        number_of_rows = self._number_of_rows

        if data is None:
            column= []

            for i in range(number_of_rows):
                column.append(self._data_vars[i][index].get())
                
            return column
        else:            
            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])

            if self._on_change_data is not None: self._on_change_data()

    def clear(self):
        number_of_rows = self._number_of_rows
        number_of_columns = self._number_of_columns

        for i in range(number_of_rows):
            for j in range(number_of_columns):
                self._data_vars[i][j].set("")

        if self._on_change_data is not None: self._on_change_data()

    def delete_row(self, index):
        i = index
        while i < self._number_of_rows:
            row_of_vars_1 = self._data_vars[i]
            row_of_vars_2 = self._data_vars[i+1]

            j = 0
            while j <self.number_of_columns:
                row_of_vars_1[j].set(row_of_vars_2[j])

            i += 1

        self._pop_n_rows(1)

        if self._on_change_data is not None: self._on_change_data()

    def insert_row(self, data, index=END):
        self._append_n_rows(1)

        if index == END:
            index = self._number_of_rows - 1
        
        i = self._number_of_rows-1
        while i > index:
            row_of_vars_1 = self._data_vars[i-1]
            row_of_vars_2 = self._data_vars[i]

            j = 0
            while j < self.number_of_columns:
                row_of_vars_2[j].set(row_of_vars_1[j])
                j += 1
            i -= 1

        list_of_cell_vars = self._data_vars[index]
        for cell_var, cell_data in zip(list_of_cell_vars, data):
            cell_var.set(cell_data)

        if self._on_change_data is not None: self._on_change_data()

    def cell(self, row, column, data=None):
        """Get the value of a table cell"""
        if data is None:
            return self._data_vars[row][column].get()
        else:
            self._data_vars[row][column].set(data)
            if self._on_change_data is not None: self._on_change_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")

    def on_change_data(self, callback):
        self._on_change_data = callback

if __name__ == "__main__":
    try:
        from Tkinter import Tk
    except ImportError:
        from tkinter import Tk

    root = Tk()

    table = Table(root, ["column A", "column B", "column C"], column_minwidths=[None, None, None])
    table.pack(padx=10,pady=10)

    table.set_data([[1,2,3],[4,5,6], [7,8,9], [10,11,12], [13,14,15],[15,16,18], [19,20,21]])
    table.cell(0,0, " a fdas fasd fasdf asdf asdfasdf asdf asdfa sdfas asd sadf ")
    
    root.update()
    root.geometry("%sx%s"%(root.winfo_reqwidth(),250))

    root.mainloop()

Diff to Previous Revision

--- revision 6 2017-05-03 22:42:12
+++ revision 7 2017-05-04 14:45:17
@@ -1,12 +1,12 @@
 # Author: Miguel Martinez Lopez
-# Version: 0.16
+# Version: 0.17
 
 try:
-    from Tkinter import Canvas, Frame, Label, Message, StringVar
+    from Tkinter import Frame, Label, Message, StringVar, Canvas
     from ttk import Scrollbar
     from Tkconstants import *
 except ImportError:
-    from tkinter import Canvas, Frame, Label, Message, StringVar
+    from tkinter import Frame, Label, Message, StringVar, Canvas
     from tkinter.ttk import Scrollbar
     from tkinter.constants import *
 
@@ -97,34 +97,21 @@
 
             widget.onMouseWheel = main_scrollbar.onMouseWheel
 
-
-class Multi_View(object):
-    def __init__(self, *args):
-        self._list_of_widgets = args
-
-    def add(self, *args):
-        self._list_of_widgets.extend(args)
-
-    def xview(self, *args):
-        for w in self._list_of_widgets:
-            w.xview(*args)
-
-    def yview(self, *args):
-        for w in self._list_of_widgets:
-            w.yview(*args)
-
 class Scrolling_Area(Frame, object):
 
-    def __init__(self, master, width=None, height=None, mousewheel_speed = 2, scroll_horizontally=True, xscrollbar=None, scroll_vertically=True, yscrollbar=None, outer_background=None, inner_frame=Frame, window_minwidth=0, window_minheight = 0, **kw):
+    def __init__(self, master, width=None, height=None, mousewheel_speed = 2, scroll_horizontally=True, xscrollbar=None, scroll_vertically=True, yscrollbar=None, outer_background=None, inner_frame=Frame, window_minwidth=None, window_minheight = None, **kw):
         Frame.__init__(self, master, class_=self.__class__)
-        
+
         if outer_background:
             self.configure(background=outer_background)
 
         self._width = width
         self._height = height
 
-        self.canvas = Canvas(self, highlightthickness=0, width=width, height=height)
+        self.grid_columnconfigure(0, weight=1)
+        self.grid_rowconfigure(0, weight=1)
+
+        self.canvas = Canvas(self, background=outer_background, highlightthickness=0, width=width, height=height)
         self.canvas.grid(row=0, column=0, sticky=N+E+W+S)
 
         self._window_minwidth = window_minwidth
@@ -166,28 +153,56 @@
 
         Mousewheel_Support(self).add_support_to(self.canvas, xscrollbar=self.xscrollbar, yscrollbar=self.yscrollbar)
 
+    @property
+    def width(self):
+        return self._width
+        
+    @property
+    def window_minwidth(self):
+        return self._window_minwidth
+        
+    @window_minwidth.setter
+    def window_minwidth(self, window_minwidth):
+        self._window_minwidth = window_minwidth
+
+    @property
+    def window_minheight(self):
+        return self._window_minheight
+        
+    @window_minheight.setter
+    def window_minheight(self, window_minheight):
+        self._window_minheight = window_minheight
+
+    @width.setter
+    def width(self, width):
+        self._width = width
+        self.canvas.configure(width= width)
+
+    @property
+    def height(self):
+        return self._height
+        
+    @height.setter
+    def height(self, height):
+        self._height = height
+        self.canvas.configure(height = height)
+
     def _on_configure(self, event):
-        width = max(self.innerFrame.winfo_reqwidth(), event.width, self._window_minwidth)
-        height = max(self.innerFrame.winfo_reqheight(), event.height, self._window_minheight)
-
+        if self._window_minwidth is not None:
+            width = max(event.width, self._window_minwidth)
+        else:
+            width = max(self.innerFrame.winfo_reqwidth(), event.width)
+            
+        if self._window_minheight is not None:
+            height = max(event.height, self._window_minheight)
+        else:
+            height = max(self.innerFrame.winfo_reqheight(), event.height)
+
+
+        self.update_viewport(width, height)
+
+    def update_viewport(self, width, height):
         self.canvas.configure(scrollregion="0 0 %s %s" % (width, height))
-        self.canvas.itemconfigure("inner_frame", width=width, height=height)
-
-    def update_viewport(self):
-        self.update()
-
-        height = self.innerFrame.winfo_reqheight()
-        width = self.innerFrame.winfo_reqwidth()
-
-        canvas_width = self._width
-        if canvas_width is None:
-            canvas_width = width
-
-        canvas_height = self._height
-        if canvas_height is None:
-            canvas_height = height
-
-        self.canvas.configure(width=canvas_width, height=canvas_height, scrollregion="0 0 %s %s" % (width, height))
         self.canvas.itemconfigure("inner_frame", width=width, height=height)
 
 class Cell(Frame):
@@ -199,11 +214,6 @@
 
         self._message_widget = Message(self, textvariable=variable, font=font, background=background, foreground=foreground)
         self._message_widget.pack(expand=True, padx=padx, pady=pady, anchor=anchor)
-
-        self.bind("<Configure>", self._on_configure)
-
-    def _on_configure(self, event):
-        self._message_widget.configure(width=event.width)
 
 class Header_Cell(Cell):
     def __init__(self, master, text, bordercolor=None, borderwidth=1, padx=0, pady=0, background=None, foreground=None, font=None, anchor=CENTER, separator=True):
@@ -277,21 +287,23 @@
                 yscrollbar = None
 
             scrolling_area = Scrolling_Area(self, width=self._head.winfo_reqwidth(), height=height, scroll_horizontally=scroll_horizontally, xscrollbar=xscrollbar, scroll_vertically=scroll_vertically, yscrollbar=yscrollbar)
-            scrolling_area.grid(row=1, column=0, sticky=E+W)
+            scrolling_area.grid(row=1, column=0, sticky=N+E+W+S)
 
             self._body = Frame(scrolling_area.innerFrame, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=outerborder_width, bd= 0)
             self._body.pack()
             
-            if on_change_data is None:
-                on_change_data = scrolling_area.update_viewport
-            else:
-                _on_change_data = on_change_data
-                def on_change_data():
-                    scrolling_area.update_viewport()
+            _on_change_data = on_change_data
+            def on_change_data():
+                self.update()
+                width = self._body.winfo_reqwidth()
+
+                scrolling_area.update_viewport(width=width, height=self._body.winfo_reqheight())
+                
+                if _on_change_data is not None:
                     _on_change_data()
         else:
             self._body = Frame(self, height=height, highlightbackground=bordercolor, highlightcolor=bordercolor, highlightthickness=outerborder_width, bd= 0)
-            self._body.grid(row=1, column=0, sticky=E+W)
+            self._body.grid(row=1, column=0, sticky=N+E+W+S)
 
         if column_weights is None:
             for j in range(len(columns)):
@@ -524,5 +536,7 @@
     table.set_data([[1,2,3],[4,5,6], [7,8,9], [10,11,12], [13,14,15],[15,16,18], [19,20,21]])
     table.cell(0,0, " a fdas fasd fasdf asdf asdfasdf asdf asdfa sdfas asd sadf ")
     
+    root.update()
     root.geometry("%sx%s"%(root.winfo_reqwidth(),250))
+
     root.mainloop()

History