# Version 1.1
# Author: Miguel Martinez Lopez
# Uncomment the next line to see my email
# print "Email: ", "61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex")
from __future__ import print_function
from collections import defaultdict
import itertools
try:
from tkinter import *
except ImportError:
from Tkinter import *
class GridWithPanes(Frame):
def __init__(self, master, orient=HORIZONTAL, minsize=20, columnWidths = {}, rowHeights={}, fixedPanes = []):
Frame.__init__(self,master)
if orient in (HORIZONTAL, VERTICAL):
self.orient = orient
else:
raise Exception("orient must be 'horizontal' or 'vertical, not '%s'." % orient)
if type(minsize) is int:
self.minsize = minsize
else:
raise Exception("Minsize must be an integer.")
self.fixedPanes = set(fixedPanes)
self.__packSideBetweenPanes = LEFT if self.orient == HORIZONTAL else TOP
self.__packSideInsidePane = TOP if self.orient == HORIZONTAL else LEFT
self.__cellFill = X if self.orient == HORIZONTAL else Y
self.userDefinedWidths = columnWidths
self.userDefinedHeights = rowHeights
self.__panes = {}
self.is_builded = False
self.clear_table()
self.is_displayed = False
def clear_table(self):
if not self.is_builded:
self.__gridOfWidgets = {}
self.__rows = defaultdict(set)
self.__columns = defaultdict(set)
self.__rowHeights = {}
self.__columnWidths = {}
self.userDefinedWidths = {}
self.userDefinedHeights = {}
self.calculate_dimensions = True
else:
raise Exception("You can't clear the table one this is is_builded.")
@property
def rowIndices(self):
return self.__rows.keys()
@property
def columnIndices(self):
return self.__columns.keys()
@property
def numberOfRows(self):
return len(self.__rows)
@property
def numberOfColumns(self):
return len(self.__columns)
def update_cell(self, coordinates, widget):
if not self.is_builded:
raise Exception("First you must to build the GridWithPanes.")
if coordinates in self.__gridOfWidgets:
master = self.__gridOfWidgets[coordinates].pack_info()['in']
self.__gridOfWidgets[coordinates].destroy()
self.__gridOfWidgets[coordinates] = widget
widget.pack(in_=master, expand=YES, fill=BOTH)
else:
raise Exception("There is no widget with coordiantes: %s." % coordinates)
def build(self):
if self.is_builded:
raise Exception("You have just is_builded the grid before.")
if not self.__gridOfWidgets: return
if self.calculate_dimensions:
self.__calculate_list_of_cell_widths_and_heights()
self.panedwindows = []
listOfCellCoordinates = list(itertools.product(self.__rows, self.__columns))
if self.orient == HORIZONTAL:
listOfCellCoordinates.sort(key = lambda item: (item[1], item[0]))
else:
listOfCellCoordinates.sort()
# We set up the first pane index
pane_index = self.__columns[0] if self.orient == HORIZONTAL else self.__rows[0]
position_of_main_index = 1 if self.orient == HORIZONTAL else 0
newPanedWindow = True
for cell_coordinates in listOfCellCoordinates:
main_index = cell_coordinates[position_of_main_index]
if pane_index != main_index:
# Creating a new pane
pane_index = main_index
if pane_index in self.fixedPanes:
frameOfPane = Frame(self)
frameOfPane.pack(side=self.__packSideBetweenPanes)
newPanedWindow = True
else:
if newPanedWindow:
paneMaster = PanedWindow(self,orient=self.orient, bd=0, sashwidth=3)
paneMaster.index_range = (pane_index, pane_index + 1 )
paneMaster.pack(side=self.__packSideBetweenPanes)
self.panedwindows.append(paneMaster)
newPanedWindow = False
else:
beginning_of_range = paneMaster.index_range[0]
ending_of_range = pane_index + 1
paneMaster.index_range = (beginning_of_range, ending_of_range)
frameOfPane = Frame(paneMaster)
frameOfPane.pack()
paneMaster.add(frameOfPane)
paneMaster.paneconfigure(frameOfPane, minsize=self.minsize)
sizeOfPane = self.__columnWidths[pane_index] if self.orient == HORIZONTAL else self.__rowHeights[pane_index]
if self.orient == HORIZONTAL:
frameOfPane.configure(width=sizeOfPane, height=self.tableHeight)
else:
frameOfPane.configure(width=self.tableWidth, height=sizeOfPane)
frameOfPane.pack_propagate(False)
self.__panes[pane_index] = frameOfPane
cellFrame = Frame(frameOfPane, bd=1, relief=SUNKEN)
cellFrame.pack(side=self.__packSideInsidePane, expand=YES, fill=self.__cellFill)
cellFrame.pack_propagate(False)
widget = self.__gridOfWidgets[cell_coordinates]
if widget:
widget.lift()
widget.pack(in_=cellFrame, expand=YES, fill=BOTH)
if self.orient == HORIZONTAL:
cellFrame.configure( height=self.__rowHeights[ cell_coordinates[0] ] )
else:
cellFrame.configure( width=self.__columnWidths[ cell_coordinates[1] ] )
self.is_builded = True
def __calculate_list_of_cell_widths_and_heights(self):
self.__rowHeights = self.userDefinedHeights.copy()
self.__columnWidths = self.userDefinedWidths.copy()
for coordinate, widget in self.__gridOfWidgets.items():
i , j = coordinate
if i not in self.userDefinedHeights:
self.__rowHeights[i] = max(self.__rowHeights.get(i,0),widget.winfo_reqheight())
if j not in self.userDefinedWidths:
self.__columnWidths[j] = max(self.__columnWidths.get(j,0),widget.winfo_reqwidth())
self.calculate_dimensions = False
@property
def tableHeight(self):
if self.calculate_dimensions:
self.__calculate_list_of_cell_widths_and_heights()
return sum(self.__rowHeights.values())
@property
def tableWidth(self):
if self.calculate_dimensions:
self.__calculate_list_of_cell_widths_and_heights()
return sum(self.__columnWidths.values())
def rowconfigure(self,row, height=None, fixed = None):
if type(row) is str: row = int(row)
if row not in self.__rows:
raise Exception("Row %d doesn't exists." % row)
if fixed is not None:
if self.orient == HORIZONTAL:
raise Exception("You can't set fixed property on a row because 'orient' is VERTICAL.")
self.fix_pane(index, fixed)
if height is not None:
if type(height) is not int: raise Exception("The height must be an integer:%s"%height)
self.userDefinedHeights[row] = height
self.__rowHeights[row] = height
self.calculate_dimensions = True
if self.is_builded:
if self.orient == VERTICAL:
if self.is_a_fixed_pane(row):
self.__panes[row].configure(height=height)
else:
self.__set_mobile_pane_size(row, height)
else:
for column in self.__rows[row]:
cellFrame = self.__gridOfWidgets[row,column].pack_info()['in']
cellFrame.configure(height=height)
def columnconfigure(self,column, width=None, fixed = None):
if type(column) is str: column = int(column)
if column not in self.__columns:
raise Exception("Column %d doesn't exists." % column)
if fixed is not None:
if self.orient == VERTICAL:
raise Exception("You can't set fixed property on a column because 'orient' is HORIZONTAL.")
self.fix_pane(index, fixed)
if width is not None:
if type(width) is not int: raise Exception("The width must be an integer:%s"%width)
self.userDefinedWidths[column] = width
self.__columnWidths[column] = width
self.calculate_dimensions = True
if self.is_builded:
if self.orient == HORIZONTAL:
if self.is_a_fixed_pane(column):
self.__panes[column].configure(width=width)
else:
self.__set_mobile_pane_size(column, width)
else:
for row in self.__columns[column]:
cellFrame = self.__gridOfWidgets[row,column].pack_info()['in']
cellFrame.configure(width=width)
def fix_pane(index, fixed=True):
if self.is_builded:
raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
if fixed == True:
self.fixedPanes.add(index)
elif fixed == False:
self.fixedPanes.discard(index)
else:
raise Exception("fixed must be 'True' or 'False'.")
def fix_all_panes(self):
if self.is_builded:
raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
fixedPanes_list = self.__columns.keys() if self.orient == HORIZONTAL else self.__rows.keys()
self.fixedPanes = set(fixedPanes_list)
def realease_all_panes(self):
if self.is_builded:
raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
self.fixedPanes = set()
def is_a_fixed_pane(self, index ):
paneWidget = self.__panes[index]
parent = self.nametowidget( paneWidget.winfo_parent() )
if parent.winfo_class() == 'Panedwindow':
return False
else:
return True
def __get_panedwindow_INFO(self, index):
panedwindow = self.nametowidget( self.__panes[index].winfo_parent() )
panedwindow_index = index - panedwindow.index_range[0]
return panedwindow, panedwindow_index
def __set_mobile_pane_size(self, index, size):
panedwindow, panedwindow_index = self.__get_panedwindow_INFO(index)
self.__set_pane_size_in_panedwindow(panedwindow, panedwindow_index, size)
def __get_mobile_pane_size(self, index):
panedwindow, panedwindow_index = self.__get_panedwindow_INFO(index)
return self.__get_pane_size_in_panedwindow(panedwindow, panedwindow_index)
def __set_pane_size_in_panedwindow(self,panedwindow, index, size):
sash_coordinates = [0,0]
last_index = len(panedwindow.panes()) - 1
if panedwindow['orient'] == HORIZONTAL:
# Coordinate X
position_coord = 0
method_for_size_info = 'winfo_reqwidth'
else:
# Coordinate Y
position_coord = 1
method_for_size_info = 'winfo_reqheight'
if index == 0:
sash_index = 0
new_position = size
elif index == last_index:
sash_index = last_index - 1
new_position = getattr(panedwindow, method_for_size_info)() - 2*panedwindow['bd'] \
- panedwindow['sashpad'] - panedwindow['sashwidth'] \
- size
else:
sash_index = index - 1
new_position = panedwindow.sash_coord(index)[position_coord] \
- panedwindow['sashpad'] - panedwindow['sashwidth'] \
- size
sash_coordinates[position_coord] = new_position
panedwindow.sash_place(sash_index, *sash_coordinates)
def __get_pane_size_in_panedwindow(self, panedwindow, index):
if panedwindow['orient'] == HORIZONTAL:
# Coordinate X
position_coord = 0
method_for_size_info = 'winfo_reqwidth'
else:
# Coordinate Y
position_coord = 1
method_for_size_info = 'winfo_reqwidth'
last_index = len(panedwindow.panes()) - 1
if index == 0:
pane_size = panedwindow.sash_coord(index)[position_coord]
elif index == last_index:
pane_size = getattr(panedwindow, method_for_size_info)() - 2*panedwindow['bd'] \
- panedwindow.sash_coord(index-1)[position_coord] \
- panedwindow['sashpad'] - panedwindow['sashwidth']
else:
pane_size = panedwindow.sash_coord(index)[position_coord] \
- panedwindow.sash_coord(index-1)[position_coord] \
- panedwindow['sashpad'] - panedwindow['sashwidth']
return pane_size
def get_row_height(self, row):
if self.calculate_dimensions:
self.__calculate_list_of_cell_widths_and_heights()
if self.orient == VERTICAL:
if self.is_builded:
if self.is_a_fixed_pane(row):
return self.__rowHeights[row]
else:
return self.__get_mobile_pane_size(row)
else:
return self.__rowHeights[row]
else:
return self.__rowHeights[row]
def get_column_width(self, column):
if self.calculate_dimensions:
self.__calculate_list_of_cell_widths_and_heights()
if self.orient == HORIZONTAL:
if self.is_builded:
if self.is_a_fixed_pane(column):
return self.__columnWidths[column]
else:
return self.__get_mobile_pane_size(column)
else:
return self.__columnWidths[column]
else:
return self.__columnWidths[column]
def check_coordinates(self, coordinates):
if type(coordinates) is int:
i = 0
j = coordinates
else:
try:
i, j = coordinates
if type(i) is not int or type(j) is not int:
raise Exception("Invalid coordinate")
except:
raise Exception("Invalid coordinate")
return (i,j)
def __getitem__(self, coordinates):
coordinates = self.check_coordinates(coordinates)
return self.__gridOfWidgets.get(coordinates)
def __setitem__(self,coordinates, widget):
if self.is_builded:
raise Exception("The GridWithPanes was is_builded. Use cell_update() instead.")
i , j = self.check_coordinates(coordinates)
self.__gridOfWidgets[i,j] = widget
self.__rows[i].add(j)
self.__columns[j].add(i)
self.calculate_dimensions = True
def __delitem__(self, coordinates ):
if self.is_builded:
raise Exception("The GridWithPanes was is_builded. Use cell_update() instead.")
i, j = self.check_coordinates(coordinates)
del self.__gridOfWidgets[i,j]
self.__rows[i].discard(j)
if not self.__rows[i]: del self.__rows[i]
self.__columns[j].discard(i)
if not self.__columns[j]: del self.__columns[j]
self.calculate_dimensions = True
def grid(self, *args, **kargs):
if not self.is_builded: self.build()
Frame.grid(self,*args, **kargs)
self.is_displayed = True
def pack(self, *args, **kargs):
if not self.is_builded: self.build()
Frame.pack(self,*args, **kargs)
self.is_displayed = True
def place(self, *args, **kargs):
if not self.is_builded: self.build()
Frame.place(self,*args, **kargs)
self.is_displayed = True
def test():
try:
from tkinter import ttk
except ImportError:
import ttk
root = Tk()
def table_of_random_widgets(master, numRows,numColumns, **kwargs):
import random
demo = GridWithPanes(master, **kwargs)
tkinterWidgets = (
(Label, {'text':'This is a label'}),
(Label, {'text':'This is another label', 'bg':'yellow'}),
(Checkbutton,{}),
(Button, {'text':'Click me'}),
(ttk.Combobox, {'values':('item1', 'item2','item3','item4')})
)
for i in range(numRows):
for j in range(numColumns):
widgetClass, args = random.choice(tkinterWidgets)
widget = widgetClass(demo,**args)
demo[i,j] = widget
return demo
Label(root, text="orient=VERTICAL, minsize = 20, fixed rows = [2,5]").pack(anchor=NW, pady=6, padx='2m')
table1 = table_of_random_widgets(root, numRows=6,numColumns=5, orient=VERTICAL, minsize=20, fixedPanes=[2,5])
table1.pack(anchor=NW,pady=2, padx='2m')
emptySpace = Frame(root, height =20)
emptySpace.pack()
Label(root, text='''orient=HORIZONTAL, minsize = 30, fixed columns = [2], columnWidths={0:200, 2: 150, 3:250}, rowHeights={0:150}\nOn this table we will update later the cell (1,2)''', justify=LEFT).pack(anchor=NW, pady=6, padx='2m')
table2 = table_of_random_widgets(root, numRows=3,numColumns=6, minsize=30, fixedPanes=[2], columnWidths={0:200, 2: 150, 3:250}, rowHeights={0:90})
table2.pack(anchor=NW,pady=2, padx='2m')
table2.update_cell((1,2), Label(table2,text="Cell updated",bg="green") )
emptySpace = Frame(root, height =20)
emptySpace.pack()
def show_table_data():
tableName = TableVar.get()
if tableName=='top table':
table = table1
elif tableName=='bottom table':
table = table2
else:
return
StringData = ""
StringData += "Data of the grid with panes:\n"
StringData += "\tnumber of rows: %d\n" % table.numberOfRows
StringData +="\tnumber of columns: %d\n" % table.numberOfColumns
StringData +="\tTable width: %d\n" % table.tableWidth
StringData +="\tTable height: %d\n" % table.tableHeight
StringData +="\n\tHeights:\n"
for row in table.rowIndices:
StringData += "\t\trow %s: %s\n" % (row, table.get_row_height(row) )
StringData +="\n\tWidths:\n"
for column in table.columnIndices:
StringData += "\t\tcolumn %s: %s\n" % (column, table.get_column_width(column) )
print( StringData)
def change_pane_size():
tableName = TableVar.get()
if tableName=='top table':
table = table1
elif tableName=='bottom table':
table = table2
else:
return
if table.orient == HORIZONTAL:
table.columnconfigure(PaneVar.get(),SizeVar.get() )
else:
table.rowconfigure(PaneVar.get(),SizeVar.get() )
emptySpace = Frame(root, height =40)
emptySpace.pack()
ControlArea = LabelFrame(root, text ="Control area", labelanchor=N)
ControlArea.pack(expand=YES, fill=X, padx=20)
ControlArea1 = Frame(ControlArea)
ControlArea1.pack(expand=YES, fill=X, padx = 13)
Button(ControlArea1, text="Show data of widget on console", command= lambda : show_table_data() ).pack(side=LEFT)
ControlArea2 = Frame(ControlArea)
ControlArea2.pack(expand=YES, fill=X, padx = 13)
Label(ControlArea2, text="Table: ").pack(side=LEFT)
TableVar = StringVar()
TableVar.set('top table')
OptionMenu(ControlArea2, TableVar,'top table', 'bottom table').pack(side=LEFT)
Label(ControlArea2, text="Pane index: ").pack(side=LEFT)
PaneVar = IntVar()
Pane_entry = Entry(ControlArea2, textvariable = PaneVar, width=2)
Pane_entry.pack(side=LEFT)
Pane_entry.bind('<Return>', lambda event: change_pane_size() )
Pane_entry.focus()
Label(ControlArea2, text="Size: ").pack(side=LEFT)
SizeVar = IntVar()
Size_entry = Entry(ControlArea2, textvariable = SizeVar, width=4)
Size_entry.pack(side=LEFT)
Size_entry.bind('<Return>', lambda event: change_pane_size() )
Button(ControlArea2, text="Change pane size", command = lambda: change_pane_size() ).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
test()
Diff to Previous Revision
--- revision 18 2014-09-17 19:12:42
+++ revision 19 2016-10-30 22:25:05
@@ -11,596 +11,596 @@
try:
- from tkinter import *
+ from tkinter import *
except ImportError:
- from Tkinter import *
+ from Tkinter import *
class GridWithPanes(Frame):
- def __init__(self, master, orient=HORIZONTAL, minsize=20, columnWidths = {}, rowHeights={}, fixedPanes = []):
- Frame.__init__(self,master)
-
- if orient in (HORIZONTAL, VERTICAL):
- self.orient = orient
- else:
- raise Exception("orient must be 'horizontal' or 'vertical, not '%s'." % orient)
-
- if type(minsize) is int:
- self.minsize = minsize
- else:
- raise Exception("Minsize must be an integer.")
-
- self.fixedPanes = set(fixedPanes)
-
- self.__packSideBetweenPanes = LEFT if self.orient == HORIZONTAL else TOP
- self.__packSideInsidePane = TOP if self.orient == HORIZONTAL else LEFT
- self.__cellFill = X if self.orient == HORIZONTAL else Y
-
- self.userDefinedWidths = columnWidths
- self.userDefinedHeights = rowHeights
-
- self.__panes = {}
-
- self.is_builded = False
-
- self.clear_table()
-
- self.is_displayed = False
-
- def clear_table(self):
- if not self.is_builded:
- self.__gridOfWidgets = {}
-
- self.__rows = defaultdict(set)
- self.__columns = defaultdict(set)
-
- self.__rowHeights = {}
- self.__columnWidths = {}
-
- self.userDefinedWidths = {}
- self.userDefinedHeights = {}
-
- self.calculate_dimensions = True
-
- else:
- raise Exception("You can't clear the table one this is is_builded.")
-
- @property
- def rowIndices(self):
- return self.__rows.keys()
-
- @property
- def columnIndices(self):
- return self.__columns.keys()
-
- @property
- def numberOfRows(self):
- return len(self.__rows)
-
- @property
- def numberOfColumns(self):
- return len(self.__columns)
-
- def update_cell(self, coordinates, widget):
- if not self.is_builded:
- raise Exception("First you must to build the GridWithPanes.")
-
- if coordinates in self.__gridOfWidgets:
- master = self.__gridOfWidgets[coordinates].pack_info()['in']
- self.__gridOfWidgets[coordinates].destroy()
- self.__gridOfWidgets[coordinates] = widget
- widget.pack(in_=master, expand=YES, fill=BOTH)
- else:
- raise Exception("There is no widget with coordiantes: %s." % coordinates)
-
-
- def build(self):
- if self.is_builded:
- raise Exception("You have just is_builded the grid before.")
-
- if not self.__gridOfWidgets: return
-
- if self.calculate_dimensions:
- self.__calculate_list_of_cell_widths_and_heights()
-
- self.panedwindows = []
-
- listOfCellCoordinates = list(itertools.product(self.__rows, self.__columns))
-
- if self.orient == HORIZONTAL:
- listOfCellCoordinates.sort(key = lambda item: (item[1], item[0]))
- else:
- listOfCellCoordinates.sort()
-
- # We set up the first pane index
- pane_index = self.__columns[0] if self.orient == HORIZONTAL else self.__rows[0]
-
- position_of_main_index = 1 if self.orient == HORIZONTAL else 0
-
- newPanedWindow = True
-
- for cell_coordinates in listOfCellCoordinates:
-
- main_index = cell_coordinates[position_of_main_index]
- if pane_index != main_index:
- # Creating a new pane
- pane_index = main_index
-
- if pane_index in self.fixedPanes:
- frameOfPane = Frame(self)
- frameOfPane.pack(side=self.__packSideBetweenPanes)
- newPanedWindow = True
- else:
- if newPanedWindow:
- paneMaster = PanedWindow(self,orient=self.orient, bd=0, sashwidth=3)
- paneMaster.index_range = (pane_index, pane_index + 1 )
-
- paneMaster.pack(side=self.__packSideBetweenPanes)
-
- self.panedwindows.append(paneMaster)
- newPanedWindow = False
- else:
- beginning_of_range = paneMaster.index_range[0]
- ending_of_range = pane_index + 1
- paneMaster.index_range = (beginning_of_range, ending_of_range)
-
- frameOfPane = Frame(paneMaster)
- frameOfPane.pack()
- paneMaster.add(frameOfPane)
-
- paneMaster.paneconfigure(frameOfPane, minsize=self.minsize)
-
- sizeOfPane = self.__columnWidths[pane_index] if self.orient == HORIZONTAL else self.__rowHeights[pane_index]
-
- if self.orient == HORIZONTAL:
- frameOfPane.configure(width=sizeOfPane, height=self.tableHeight)
- else:
- frameOfPane.configure(width=self.tableWidth, height=sizeOfPane)
-
- frameOfPane.pack_propagate(False)
-
- self.__panes[pane_index] = frameOfPane
-
- cellFrame = Frame(frameOfPane, bd=1, relief=SUNKEN)
- cellFrame.pack(side=self.__packSideInsidePane, expand=YES, fill=self.__cellFill)
- cellFrame.pack_propagate(False)
-
- widget = self.__gridOfWidgets[cell_coordinates]
-
- if widget:
- widget.lift()
- widget.pack(in_=cellFrame, expand=YES, fill=BOTH)
-
- if self.orient == HORIZONTAL:
- cellFrame.configure( height=self.__rowHeights[ cell_coordinates[0] ] )
- else:
- cellFrame.configure( width=self.__columnWidths[ cell_coordinates[1] ] )
-
- self.is_builded = True
-
- def __calculate_list_of_cell_widths_and_heights(self):
- self.__rowHeights = self.userDefinedHeights.copy()
- self.__columnWidths = self.userDefinedWidths.copy()
-
- for coordinate, widget in self.__gridOfWidgets.items():
- i , j = coordinate
- if i not in self.userDefinedHeights:
- self.__rowHeights[i] = max(self.__rowHeights.get(i,0),widget.winfo_reqheight())
-
- if j not in self.userDefinedWidths:
- self.__columnWidths[j] = max(self.__columnWidths.get(j,0),widget.winfo_reqwidth())
-
- self.calculate_dimensions = False
-
- @property
- def tableHeight(self):
- if self.calculate_dimensions:
- self.__calculate_list_of_cell_widths_and_heights()
-
- return sum(self.__rowHeights.values())
-
- @property
- def tableWidth(self):
- if self.calculate_dimensions:
- self.__calculate_list_of_cell_widths_and_heights()
- return sum(self.__columnWidths.values())
-
-
- def rowconfigure(self,row, height=None, fixed = None):
- if type(row) is str: row = int(row)
-
- if row not in self.__rows:
- raise Exception("Row %d doesn't exists." % row)
-
- if fixed is not None:
- if self.orient == HORIZONTAL:
- raise Exception("You can't set fixed property on a row because 'orient' is VERTICAL.")
-
- self.fix_pane(index, fixed)
-
- if height is not None:
-
- if type(height) is not int: raise Exception("The height must be an integer:%s"%height)
-
- self.userDefinedHeights[row] = height
- self.__rowHeights[row] = height
- self.calculate_dimensions = True
-
- if self.is_builded:
- if self.orient == VERTICAL:
- if self.is_a_fixed_pane(row):
- self.__panes[row].configure(height=height)
- else:
- self.__set_mobile_pane_size(row, height)
- else:
- for column in self.__rows[row]:
- cellFrame = self.__gridOfWidgets[row,column].pack_info()['in']
- cellFrame.configure(height=height)
-
-
- def columnconfigure(self,column, width=None, fixed = None):
- if type(column) is str: column = int(column)
-
- if column not in self.__columns:
- raise Exception("Column %d doesn't exists." % column)
-
- if fixed is not None:
- if self.orient == VERTICAL:
- raise Exception("You can't set fixed property on a column because 'orient' is HORIZONTAL.")
-
- self.fix_pane(index, fixed)
-
- if width is not None:
- if type(width) is not int: raise Exception("The width must be an integer:%s"%width)
-
- self.userDefinedWidths[column] = width
- self.__columnWidths[column] = width
- self.calculate_dimensions = True
-
- if self.is_builded:
- if self.orient == HORIZONTAL:
- if self.is_a_fixed_pane(column):
- self.__panes[column].configure(width=width)
- else:
- self.__set_mobile_pane_size(column, width)
- else:
- for row in self.__columns[column]:
- cellFrame = self.__gridOfWidgets[row,column].pack_info()['in']
- cellFrame.configure(width=width)
-
-
- def fix_pane(index, fixed=True):
- if self.is_builded:
- raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
-
- if fixed == True:
- self.fixedPanes.add(index)
- elif fixed == False:
- self.fixedPanes.discard(index)
- else:
- raise Exception("fixed must be 'True' or 'False'.")
-
- def fix_all_panes(self):
- if self.is_builded:
- raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
-
- fixedPanes_list = self.__columns.keys() if self.orient == HORIZONTAL else self.__rows.keys()
- self.fixedPanes = set(fixedPanes_list)
-
- def realease_all_panes(self):
- if self.is_builded:
- raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
-
- self.fixedPanes = set()
-
- def is_a_fixed_pane(self, index ):
- paneWidget = self.__panes[index]
-
- parent = self.nametowidget( paneWidget.winfo_parent() )
-
- if parent.winfo_class() == 'Panedwindow':
- return False
- else:
- return True
-
- def __get_panedwindow_INFO(self, index):
- panedwindow = self.nametowidget( self.__panes[index].winfo_parent() )
- panedwindow_index = index - panedwindow.index_range[0]
- return panedwindow, panedwindow_index
-
- def __set_mobile_pane_size(self, index, size):
- panedwindow, panedwindow_index = self.__get_panedwindow_INFO(index)
- self.__set_pane_size_in_panedwindow(panedwindow, panedwindow_index, size)
-
- def __get_mobile_pane_size(self, index):
- panedwindow, panedwindow_index = self.__get_panedwindow_INFO(index)
- return self.__get_pane_size_in_panedwindow(panedwindow, panedwindow_index)
-
- def __set_pane_size_in_panedwindow(self,panedwindow, index, size):
- sash_coordinates = [0,0]
- last_index = len(panedwindow.panes()) - 1
-
- if panedwindow['orient'] == HORIZONTAL:
- # Coordinate X
- position_coord = 0
-
- method_for_size_info = 'winfo_reqwidth'
- else:
- # Coordinate Y
- position_coord = 1
-
- method_for_size_info = 'winfo_reqheight'
-
-
- if index == 0:
- sash_index = 0
- new_position = size
- elif index == last_index:
- sash_index = last_index - 1
- new_position = getattr(panedwindow, method_for_size_info)() - 2*panedwindow['bd'] \
- - panedwindow['sashpad'] - panedwindow['sashwidth'] \
- - size
- else:
- sash_index = index - 1
- new_position = panedwindow.sash_coord(index)[position_coord] \
- - panedwindow['sashpad'] - panedwindow['sashwidth'] \
- - size
-
- sash_coordinates[position_coord] = new_position
-
- panedwindow.sash_place(sash_index, *sash_coordinates)
-
- def __get_pane_size_in_panedwindow(self, panedwindow, index):
- if panedwindow['orient'] == HORIZONTAL:
- # Coordinate X
- position_coord = 0
-
- method_for_size_info = 'winfo_reqwidth'
- else:
- # Coordinate Y
- position_coord = 1
-
- method_for_size_info = 'winfo_reqwidth'
-
- last_index = len(panedwindow.panes()) - 1
-
- if index == 0:
- pane_size = panedwindow.sash_coord(index)[position_coord]
- elif index == last_index:
- pane_size = getattr(panedwindow, method_for_size_info)() - 2*panedwindow['bd'] \
- - panedwindow.sash_coord(index-1)[position_coord] \
- - panedwindow['sashpad'] - panedwindow['sashwidth']
- else:
- pane_size = panedwindow.sash_coord(index)[position_coord] \
- - panedwindow.sash_coord(index-1)[position_coord] \
- - panedwindow['sashpad'] - panedwindow['sashwidth']
-
- return pane_size
-
- def get_row_height(self, row):
- if self.calculate_dimensions:
- self.__calculate_list_of_cell_widths_and_heights()
-
- if self.orient == VERTICAL:
- if self.is_builded:
- if self.is_a_fixed_pane(row):
- return self.__rowHeights[row]
- else:
- return self.__get_mobile_pane_size(row)
- else:
- return self.__rowHeights[row]
- else:
- return self.__rowHeights[row]
-
- def get_column_width(self, column):
- if self.calculate_dimensions:
- self.__calculate_list_of_cell_widths_and_heights()
- if self.orient == HORIZONTAL:
- if self.is_builded:
- if self.is_a_fixed_pane(column):
- return self.__columnWidths[column]
- else:
- return self.__get_mobile_pane_size(column)
- else:
- return self.__columnWidths[column]
- else:
- return self.__columnWidths[column]
-
- def check_coordinates(self, coordinates):
- if type(coordinates) is int:
- i = 0
- j = coordinates
- else:
- try:
- i, j = coordinates
- if type(i) is not int or type(j) is not int:
- raise Exception("Invalid coordinate")
- except:
- raise Exception("Invalid coordinate")
-
- return (i,j)
-
- def __getitem__(self, coordinates):
- coordinates = self.check_coordinates(coordinates)
-
- return self.__gridOfWidgets.get(coordinates)
-
-
- def __setitem__(self,coordinates, widget):
- if self.is_builded:
- raise Exception("The GridWithPanes was is_builded. Use cell_update() instead.")
-
- i , j = self.check_coordinates(coordinates)
-
- self.__gridOfWidgets[i,j] = widget
-
- self.__rows[i].add(j)
- self.__columns[j].add(i)
-
- self.calculate_dimensions = True
-
- def __delitem__(self, coordinates ):
- if self.is_builded:
- raise Exception("The GridWithPanes was is_builded. Use cell_update() instead.")
-
- i, j = self.check_coordinates(coordinates)
-
- del self.__gridOfWidgets[i,j]
-
- self.__rows[i].discard(j)
- if not self.__rows[i]: del self.__rows[i]
-
- self.__columns[j].discard(i)
- if not self.__columns[j]: del self.__columns[j]
-
- self.calculate_dimensions = True
-
- def grid(self, *args, **kargs):
- if not self.is_builded: self.build()
- Frame.grid(self,*args, **kargs)
- self.is_displayed = True
-
- def pack(self, *args, **kargs):
- if not self.is_builded: self.build()
- Frame.pack(self,*args, **kargs)
- self.is_displayed = True
-
- def place(self, *args, **kargs):
- if not self.is_builded: self.build()
- Frame.place(self,*args, **kargs)
- self.is_displayed = True
+ def __init__(self, master, orient=HORIZONTAL, minsize=20, columnWidths = {}, rowHeights={}, fixedPanes = []):
+ Frame.__init__(self,master)
+
+ if orient in (HORIZONTAL, VERTICAL):
+ self.orient = orient
+ else:
+ raise Exception("orient must be 'horizontal' or 'vertical, not '%s'." % orient)
+
+ if type(minsize) is int:
+ self.minsize = minsize
+ else:
+ raise Exception("Minsize must be an integer.")
+
+ self.fixedPanes = set(fixedPanes)
+
+ self.__packSideBetweenPanes = LEFT if self.orient == HORIZONTAL else TOP
+ self.__packSideInsidePane = TOP if self.orient == HORIZONTAL else LEFT
+ self.__cellFill = X if self.orient == HORIZONTAL else Y
+
+ self.userDefinedWidths = columnWidths
+ self.userDefinedHeights = rowHeights
+
+ self.__panes = {}
+
+ self.is_builded = False
+
+ self.clear_table()
+
+ self.is_displayed = False
+
+ def clear_table(self):
+ if not self.is_builded:
+ self.__gridOfWidgets = {}
+
+ self.__rows = defaultdict(set)
+ self.__columns = defaultdict(set)
+
+ self.__rowHeights = {}
+ self.__columnWidths = {}
+
+ self.userDefinedWidths = {}
+ self.userDefinedHeights = {}
+
+ self.calculate_dimensions = True
+
+ else:
+ raise Exception("You can't clear the table one this is is_builded.")
+
+ @property
+ def rowIndices(self):
+ return self.__rows.keys()
+
+ @property
+ def columnIndices(self):
+ return self.__columns.keys()
+
+ @property
+ def numberOfRows(self):
+ return len(self.__rows)
+
+ @property
+ def numberOfColumns(self):
+ return len(self.__columns)
+
+ def update_cell(self, coordinates, widget):
+ if not self.is_builded:
+ raise Exception("First you must to build the GridWithPanes.")
+
+ if coordinates in self.__gridOfWidgets:
+ master = self.__gridOfWidgets[coordinates].pack_info()['in']
+ self.__gridOfWidgets[coordinates].destroy()
+ self.__gridOfWidgets[coordinates] = widget
+ widget.pack(in_=master, expand=YES, fill=BOTH)
+ else:
+ raise Exception("There is no widget with coordiantes: %s." % coordinates)
+
+
+ def build(self):
+ if self.is_builded:
+ raise Exception("You have just is_builded the grid before.")
+
+ if not self.__gridOfWidgets: return
+
+ if self.calculate_dimensions:
+ self.__calculate_list_of_cell_widths_and_heights()
+
+ self.panedwindows = []
+
+ listOfCellCoordinates = list(itertools.product(self.__rows, self.__columns))
+
+ if self.orient == HORIZONTAL:
+ listOfCellCoordinates.sort(key = lambda item: (item[1], item[0]))
+ else:
+ listOfCellCoordinates.sort()
+
+ # We set up the first pane index
+ pane_index = self.__columns[0] if self.orient == HORIZONTAL else self.__rows[0]
+
+ position_of_main_index = 1 if self.orient == HORIZONTAL else 0
+
+ newPanedWindow = True
+
+ for cell_coordinates in listOfCellCoordinates:
+
+ main_index = cell_coordinates[position_of_main_index]
+ if pane_index != main_index:
+ # Creating a new pane
+ pane_index = main_index
+
+ if pane_index in self.fixedPanes:
+ frameOfPane = Frame(self)
+ frameOfPane.pack(side=self.__packSideBetweenPanes)
+ newPanedWindow = True
+ else:
+ if newPanedWindow:
+ paneMaster = PanedWindow(self,orient=self.orient, bd=0, sashwidth=3)
+ paneMaster.index_range = (pane_index, pane_index + 1 )
+
+ paneMaster.pack(side=self.__packSideBetweenPanes)
+
+ self.panedwindows.append(paneMaster)
+ newPanedWindow = False
+ else:
+ beginning_of_range = paneMaster.index_range[0]
+ ending_of_range = pane_index + 1
+ paneMaster.index_range = (beginning_of_range, ending_of_range)
+
+ frameOfPane = Frame(paneMaster)
+ frameOfPane.pack()
+ paneMaster.add(frameOfPane)
+
+ paneMaster.paneconfigure(frameOfPane, minsize=self.minsize)
+
+ sizeOfPane = self.__columnWidths[pane_index] if self.orient == HORIZONTAL else self.__rowHeights[pane_index]
+
+ if self.orient == HORIZONTAL:
+ frameOfPane.configure(width=sizeOfPane, height=self.tableHeight)
+ else:
+ frameOfPane.configure(width=self.tableWidth, height=sizeOfPane)
+
+ frameOfPane.pack_propagate(False)
+
+ self.__panes[pane_index] = frameOfPane
+
+ cellFrame = Frame(frameOfPane, bd=1, relief=SUNKEN)
+ cellFrame.pack(side=self.__packSideInsidePane, expand=YES, fill=self.__cellFill)
+ cellFrame.pack_propagate(False)
+
+ widget = self.__gridOfWidgets[cell_coordinates]
+
+ if widget:
+ widget.lift()
+ widget.pack(in_=cellFrame, expand=YES, fill=BOTH)
+
+ if self.orient == HORIZONTAL:
+ cellFrame.configure( height=self.__rowHeights[ cell_coordinates[0] ] )
+ else:
+ cellFrame.configure( width=self.__columnWidths[ cell_coordinates[1] ] )
+
+ self.is_builded = True
+
+ def __calculate_list_of_cell_widths_and_heights(self):
+ self.__rowHeights = self.userDefinedHeights.copy()
+ self.__columnWidths = self.userDefinedWidths.copy()
+
+ for coordinate, widget in self.__gridOfWidgets.items():
+ i , j = coordinate
+ if i not in self.userDefinedHeights:
+ self.__rowHeights[i] = max(self.__rowHeights.get(i,0),widget.winfo_reqheight())
+
+ if j not in self.userDefinedWidths:
+ self.__columnWidths[j] = max(self.__columnWidths.get(j,0),widget.winfo_reqwidth())
+
+ self.calculate_dimensions = False
+
+ @property
+ def tableHeight(self):
+ if self.calculate_dimensions:
+ self.__calculate_list_of_cell_widths_and_heights()
+
+ return sum(self.__rowHeights.values())
+
+ @property
+ def tableWidth(self):
+ if self.calculate_dimensions:
+ self.__calculate_list_of_cell_widths_and_heights()
+ return sum(self.__columnWidths.values())
+
+
+ def rowconfigure(self,row, height=None, fixed = None):
+ if type(row) is str: row = int(row)
+
+ if row not in self.__rows:
+ raise Exception("Row %d doesn't exists." % row)
+
+ if fixed is not None:
+ if self.orient == HORIZONTAL:
+ raise Exception("You can't set fixed property on a row because 'orient' is VERTICAL.")
+
+ self.fix_pane(index, fixed)
+
+ if height is not None:
+
+ if type(height) is not int: raise Exception("The height must be an integer:%s"%height)
+
+ self.userDefinedHeights[row] = height
+ self.__rowHeights[row] = height
+ self.calculate_dimensions = True
+
+ if self.is_builded:
+ if self.orient == VERTICAL:
+ if self.is_a_fixed_pane(row):
+ self.__panes[row].configure(height=height)
+ else:
+ self.__set_mobile_pane_size(row, height)
+ else:
+ for column in self.__rows[row]:
+ cellFrame = self.__gridOfWidgets[row,column].pack_info()['in']
+ cellFrame.configure(height=height)
+
+
+ def columnconfigure(self,column, width=None, fixed = None):
+ if type(column) is str: column = int(column)
+
+ if column not in self.__columns:
+ raise Exception("Column %d doesn't exists." % column)
+
+ if fixed is not None:
+ if self.orient == VERTICAL:
+ raise Exception("You can't set fixed property on a column because 'orient' is HORIZONTAL.")
+
+ self.fix_pane(index, fixed)
+
+ if width is not None:
+ if type(width) is not int: raise Exception("The width must be an integer:%s"%width)
+
+ self.userDefinedWidths[column] = width
+ self.__columnWidths[column] = width
+ self.calculate_dimensions = True
+
+ if self.is_builded:
+ if self.orient == HORIZONTAL:
+ if self.is_a_fixed_pane(column):
+ self.__panes[column].configure(width=width)
+ else:
+ self.__set_mobile_pane_size(column, width)
+ else:
+ for row in self.__columns[column]:
+ cellFrame = self.__gridOfWidgets[row,column].pack_info()['in']
+ cellFrame.configure(width=width)
+
+
+ def fix_pane(index, fixed=True):
+ if self.is_builded:
+ raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
+
+ if fixed == True:
+ self.fixedPanes.add(index)
+ elif fixed == False:
+ self.fixedPanes.discard(index)
+ else:
+ raise Exception("fixed must be 'True' or 'False'.")
+
+ def fix_all_panes(self):
+ if self.is_builded:
+ raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
+
+ fixedPanes_list = self.__columns.keys() if self.orient == HORIZONTAL else self.__rows.keys()
+ self.fixedPanes = set(fixedPanes_list)
+
+ def realease_all_panes(self):
+ if self.is_builded:
+ raise Exception("You can't modify the fixed of the panes once you is_builded the grid.")
+
+ self.fixedPanes = set()
+
+ def is_a_fixed_pane(self, index ):
+ paneWidget = self.__panes[index]
+
+ parent = self.nametowidget( paneWidget.winfo_parent() )
+
+ if parent.winfo_class() == 'Panedwindow':
+ return False
+ else:
+ return True
+
+ def __get_panedwindow_INFO(self, index):
+ panedwindow = self.nametowidget( self.__panes[index].winfo_parent() )
+ panedwindow_index = index - panedwindow.index_range[0]
+ return panedwindow, panedwindow_index
+
+ def __set_mobile_pane_size(self, index, size):
+ panedwindow, panedwindow_index = self.__get_panedwindow_INFO(index)
+ self.__set_pane_size_in_panedwindow(panedwindow, panedwindow_index, size)
+
+ def __get_mobile_pane_size(self, index):
+ panedwindow, panedwindow_index = self.__get_panedwindow_INFO(index)
+ return self.__get_pane_size_in_panedwindow(panedwindow, panedwindow_index)
+
+ def __set_pane_size_in_panedwindow(self,panedwindow, index, size):
+ sash_coordinates = [0,0]
+ last_index = len(panedwindow.panes()) - 1
+
+ if panedwindow['orient'] == HORIZONTAL:
+ # Coordinate X
+ position_coord = 0
+
+ method_for_size_info = 'winfo_reqwidth'
+ else:
+ # Coordinate Y
+ position_coord = 1
+
+ method_for_size_info = 'winfo_reqheight'
+
+
+ if index == 0:
+ sash_index = 0
+ new_position = size
+ elif index == last_index:
+ sash_index = last_index - 1
+ new_position = getattr(panedwindow, method_for_size_info)() - 2*panedwindow['bd'] \
+ - panedwindow['sashpad'] - panedwindow['sashwidth'] \
+ - size
+ else:
+ sash_index = index - 1
+ new_position = panedwindow.sash_coord(index)[position_coord] \
+ - panedwindow['sashpad'] - panedwindow['sashwidth'] \
+ - size
+
+ sash_coordinates[position_coord] = new_position
+
+ panedwindow.sash_place(sash_index, *sash_coordinates)
+
+ def __get_pane_size_in_panedwindow(self, panedwindow, index):
+ if panedwindow['orient'] == HORIZONTAL:
+ # Coordinate X
+ position_coord = 0
+
+ method_for_size_info = 'winfo_reqwidth'
+ else:
+ # Coordinate Y
+ position_coord = 1
+
+ method_for_size_info = 'winfo_reqwidth'
+
+ last_index = len(panedwindow.panes()) - 1
+
+ if index == 0:
+ pane_size = panedwindow.sash_coord(index)[position_coord]
+ elif index == last_index:
+ pane_size = getattr(panedwindow, method_for_size_info)() - 2*panedwindow['bd'] \
+ - panedwindow.sash_coord(index-1)[position_coord] \
+ - panedwindow['sashpad'] - panedwindow['sashwidth']
+ else:
+ pane_size = panedwindow.sash_coord(index)[position_coord] \
+ - panedwindow.sash_coord(index-1)[position_coord] \
+ - panedwindow['sashpad'] - panedwindow['sashwidth']
+
+ return pane_size
+
+ def get_row_height(self, row):
+ if self.calculate_dimensions:
+ self.__calculate_list_of_cell_widths_and_heights()
+
+ if self.orient == VERTICAL:
+ if self.is_builded:
+ if self.is_a_fixed_pane(row):
+ return self.__rowHeights[row]
+ else:
+ return self.__get_mobile_pane_size(row)
+ else:
+ return self.__rowHeights[row]
+ else:
+ return self.__rowHeights[row]
+
+ def get_column_width(self, column):
+ if self.calculate_dimensions:
+ self.__calculate_list_of_cell_widths_and_heights()
+ if self.orient == HORIZONTAL:
+ if self.is_builded:
+ if self.is_a_fixed_pane(column):
+ return self.__columnWidths[column]
+ else:
+ return self.__get_mobile_pane_size(column)
+ else:
+ return self.__columnWidths[column]
+ else:
+ return self.__columnWidths[column]
+
+ def check_coordinates(self, coordinates):
+ if type(coordinates) is int:
+ i = 0
+ j = coordinates
+ else:
+ try:
+ i, j = coordinates
+ if type(i) is not int or type(j) is not int:
+ raise Exception("Invalid coordinate")
+ except:
+ raise Exception("Invalid coordinate")
+
+ return (i,j)
+
+ def __getitem__(self, coordinates):
+ coordinates = self.check_coordinates(coordinates)
+
+ return self.__gridOfWidgets.get(coordinates)
+
+
+ def __setitem__(self,coordinates, widget):
+ if self.is_builded:
+ raise Exception("The GridWithPanes was is_builded. Use cell_update() instead.")
+
+ i , j = self.check_coordinates(coordinates)
+
+ self.__gridOfWidgets[i,j] = widget
+
+ self.__rows[i].add(j)
+ self.__columns[j].add(i)
+
+ self.calculate_dimensions = True
+
+ def __delitem__(self, coordinates ):
+ if self.is_builded:
+ raise Exception("The GridWithPanes was is_builded. Use cell_update() instead.")
+
+ i, j = self.check_coordinates(coordinates)
+
+ del self.__gridOfWidgets[i,j]
+
+ self.__rows[i].discard(j)
+ if not self.__rows[i]: del self.__rows[i]
+
+ self.__columns[j].discard(i)
+ if not self.__columns[j]: del self.__columns[j]
+
+ self.calculate_dimensions = True
+
+ def grid(self, *args, **kargs):
+ if not self.is_builded: self.build()
+ Frame.grid(self,*args, **kargs)
+ self.is_displayed = True
+
+ def pack(self, *args, **kargs):
+ if not self.is_builded: self.build()
+ Frame.pack(self,*args, **kargs)
+ self.is_displayed = True
+
+ def place(self, *args, **kargs):
+ if not self.is_builded: self.build()
+ Frame.place(self,*args, **kargs)
+ self.is_displayed = True
def test():
- try:
- from tkinter import ttk
- except ImportError:
- import ttk
-
- root = Tk()
-
- def table_of_random_widgets(master, numRows,numColumns, **kwargs):
- import random
- demo = GridWithPanes(master, **kwargs)
-
- tkinterWidgets = (
- (Label, {'text':'This is a label'}),
- (Label, {'text':'This is another label', 'bg':'yellow'}),
- (Checkbutton,{}),
- (Button, {'text':'Click me'}),
- (ttk.Combobox, {'values':('item1', 'item2','item3','item4')})
- )
-
- for i in range(numRows):
- for j in range(numColumns):
- widgetClass, args = random.choice(tkinterWidgets)
- widget = widgetClass(demo,**args)
-
- demo[i,j] = widget
-
- return demo
-
- Label(root, text="orient=VERTICAL, minsize = 20, fixed rows = [2,5]").pack(anchor=NW, pady=6, padx='2m')
- table1 = table_of_random_widgets(root, numRows=6,numColumns=5, orient=VERTICAL, minsize=20, fixedPanes=[2,5])
- table1.pack(anchor=NW,pady=2, padx='2m')
-
- emptySpace = Frame(root, height =20)
- emptySpace.pack()
-
-
- Label(root, text='''orient=HORIZONTAL, minsize = 30, fixed columns = [2], columnWidths={0:200, 2: 150, 3:250}, rowHeights={0:150}\nOn this table we will update later the cell (1,2)''', justify=LEFT).pack(anchor=NW, pady=6, padx='2m')
-
- table2 = table_of_random_widgets(root, numRows=3,numColumns=6, minsize=30, fixedPanes=[2], columnWidths={0:200, 2: 150, 3:250}, rowHeights={0:90})
- table2.pack(anchor=NW,pady=2, padx='2m')
-
- table2.update_cell((1,2), Label(table2,text="Cell updated",bg="green") )
-
- emptySpace = Frame(root, height =20)
- emptySpace.pack()
-
- def show_table_data():
- tableName = TableVar.get()
- if tableName=='top table':
- table = table1
- elif tableName=='bottom table':
- table = table2
- else:
- return
-
- StringData = ""
-
- StringData += "Data of the grid with panes:\n"
- StringData += "\tnumber of rows: %d\n" % table.numberOfRows
- StringData +="\tnumber of columns: %d\n" % table.numberOfColumns
- StringData +="\tTable width: %d\n" % table.tableWidth
- StringData +="\tTable height: %d\n" % table.tableHeight
-
- StringData +="\n\tHeights:\n"
-
- for row in table.rowIndices:
- StringData += "\t\trow %s: %s\n" % (row, table.get_row_height(row) )
-
- StringData +="\n\tWidths:\n"
-
- for column in table.columnIndices:
- StringData += "\t\tcolumn %s: %s\n" % (column, table.get_column_width(column) )
-
- print( StringData)
-
- def change_pane_size():
- tableName = TableVar.get()
-
- if tableName=='top table':
- table = table1
- elif tableName=='bottom table':
- table = table2
- else:
- return
-
- if table.orient == HORIZONTAL:
- table.columnconfigure(PaneVar.get(),SizeVar.get() )
- else:
- table.rowconfigure(PaneVar.get(),SizeVar.get() )
-
- emptySpace = Frame(root, height =40)
- emptySpace.pack()
-
- ControlArea = LabelFrame(root, text ="Control area", labelanchor=N)
- ControlArea.pack(expand=YES, fill=X, padx=20)
-
- ControlArea1 = Frame(ControlArea)
- ControlArea1.pack(expand=YES, fill=X, padx = 13)
-
- Button(ControlArea1, text="Show data of widget on console", command= lambda : show_table_data() ).pack(side=LEFT)
-
- ControlArea2 = Frame(ControlArea)
- ControlArea2.pack(expand=YES, fill=X, padx = 13)
-
- Label(ControlArea2, text="Table: ").pack(side=LEFT)
- TableVar = StringVar()
- TableVar.set('top table')
- OptionMenu(ControlArea2, TableVar,'top table', 'bottom table').pack(side=LEFT)
-
-
- Label(ControlArea2, text="Pane index: ").pack(side=LEFT)
- PaneVar = IntVar()
- Pane_entry = Entry(ControlArea2, textvariable = PaneVar, width=2)
- Pane_entry.pack(side=LEFT)
- Pane_entry.bind('<Return>', lambda event: change_pane_size() )
- Pane_entry.focus()
-
-
- Label(ControlArea2, text="Size: ").pack(side=LEFT)
- SizeVar = IntVar()
- Size_entry = Entry(ControlArea2, textvariable = SizeVar, width=4)
- Size_entry.pack(side=LEFT)
- Size_entry.bind('<Return>', lambda event: change_pane_size() )
-
-
- Button(ControlArea2, text="Change pane size", command = lambda: change_pane_size() ).pack(side=LEFT)
-
- root.mainloop()
+ try:
+ from tkinter import ttk
+ except ImportError:
+ import ttk
+
+ root = Tk()
+
+ def table_of_random_widgets(master, numRows,numColumns, **kwargs):
+ import random
+ demo = GridWithPanes(master, **kwargs)
+
+ tkinterWidgets = (
+ (Label, {'text':'This is a label'}),
+ (Label, {'text':'This is another label', 'bg':'yellow'}),
+ (Checkbutton,{}),
+ (Button, {'text':'Click me'}),
+ (ttk.Combobox, {'values':('item1', 'item2','item3','item4')})
+ )
+
+ for i in range(numRows):
+ for j in range(numColumns):
+ widgetClass, args = random.choice(tkinterWidgets)
+ widget = widgetClass(demo,**args)
+
+ demo[i,j] = widget
+
+ return demo
+
+ Label(root, text="orient=VERTICAL, minsize = 20, fixed rows = [2,5]").pack(anchor=NW, pady=6, padx='2m')
+ table1 = table_of_random_widgets(root, numRows=6,numColumns=5, orient=VERTICAL, minsize=20, fixedPanes=[2,5])
+ table1.pack(anchor=NW,pady=2, padx='2m')
+
+ emptySpace = Frame(root, height =20)
+ emptySpace.pack()
+
+
+ Label(root, text='''orient=HORIZONTAL, minsize = 30, fixed columns = [2], columnWidths={0:200, 2: 150, 3:250}, rowHeights={0:150}\nOn this table we will update later the cell (1,2)''', justify=LEFT).pack(anchor=NW, pady=6, padx='2m')
+
+ table2 = table_of_random_widgets(root, numRows=3,numColumns=6, minsize=30, fixedPanes=[2], columnWidths={0:200, 2: 150, 3:250}, rowHeights={0:90})
+ table2.pack(anchor=NW,pady=2, padx='2m')
+
+ table2.update_cell((1,2), Label(table2,text="Cell updated",bg="green") )
+
+ emptySpace = Frame(root, height =20)
+ emptySpace.pack()
+
+ def show_table_data():
+ tableName = TableVar.get()
+ if tableName=='top table':
+ table = table1
+ elif tableName=='bottom table':
+ table = table2
+ else:
+ return
+
+ StringData = ""
+
+ StringData += "Data of the grid with panes:\n"
+ StringData += "\tnumber of rows: %d\n" % table.numberOfRows
+ StringData +="\tnumber of columns: %d\n" % table.numberOfColumns
+ StringData +="\tTable width: %d\n" % table.tableWidth
+ StringData +="\tTable height: %d\n" % table.tableHeight
+
+ StringData +="\n\tHeights:\n"
+
+ for row in table.rowIndices:
+ StringData += "\t\trow %s: %s\n" % (row, table.get_row_height(row) )
+
+ StringData +="\n\tWidths:\n"
+
+ for column in table.columnIndices:
+ StringData += "\t\tcolumn %s: %s\n" % (column, table.get_column_width(column) )
+
+ print( StringData)
+
+ def change_pane_size():
+ tableName = TableVar.get()
+
+ if tableName=='top table':
+ table = table1
+ elif tableName=='bottom table':
+ table = table2
+ else:
+ return
+
+ if table.orient == HORIZONTAL:
+ table.columnconfigure(PaneVar.get(),SizeVar.get() )
+ else:
+ table.rowconfigure(PaneVar.get(),SizeVar.get() )
+
+ emptySpace = Frame(root, height =40)
+ emptySpace.pack()
+
+ ControlArea = LabelFrame(root, text ="Control area", labelanchor=N)
+ ControlArea.pack(expand=YES, fill=X, padx=20)
+
+ ControlArea1 = Frame(ControlArea)
+ ControlArea1.pack(expand=YES, fill=X, padx = 13)
+
+ Button(ControlArea1, text="Show data of widget on console", command= lambda : show_table_data() ).pack(side=LEFT)
+
+ ControlArea2 = Frame(ControlArea)
+ ControlArea2.pack(expand=YES, fill=X, padx = 13)
+
+ Label(ControlArea2, text="Table: ").pack(side=LEFT)
+ TableVar = StringVar()
+ TableVar.set('top table')
+ OptionMenu(ControlArea2, TableVar,'top table', 'bottom table').pack(side=LEFT)
+
+
+ Label(ControlArea2, text="Pane index: ").pack(side=LEFT)
+ PaneVar = IntVar()
+ Pane_entry = Entry(ControlArea2, textvariable = PaneVar, width=2)
+ Pane_entry.pack(side=LEFT)
+ Pane_entry.bind('<Return>', lambda event: change_pane_size() )
+ Pane_entry.focus()
+
+
+ Label(ControlArea2, text="Size: ").pack(side=LEFT)
+ SizeVar = IntVar()
+ Size_entry = Entry(ControlArea2, textvariable = SizeVar, width=4)
+ Size_entry.pack(side=LEFT)
+ Size_entry.bind('<Return>', lambda event: change_pane_size() )
+
+
+ Button(ControlArea2, text="Change pane size", command = lambda: change_pane_size() ).pack(side=LEFT)
+
+ root.mainloop()
if __name__ == '__main__':
- test()
+ test()