# Author: Miguel Martinez Lopez
#
# Version: 0.1
# Uncomment the next line to see my email
# print("Author's email: %s"%"61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))
try:
from Tkinter import PhotoImage, Frame, Label
from Tkconstants import *
except ImportError:
from tkinter import PhotoImage, Frame, Label
from tkinter.constants import *
class CollapsibleFrame(Frame):
def __init__(self, master, text, borderwidth=2, inner_width=0, inner_height=16, ipadx=0, ipady=8, background=None, caption_separation=4, caption_font=None, button_padx=3):
Frame.__init__(self, master)
if background is None:
background = self.cget("background")
self.configure(background=background)
self._is_opened = False
self._ipadx=ipadx
self._ipady=ipady
self._iconOpen = PhotoImage(data="R0lGODlhEAAQAKIAAP///9TQyICAgEBAQAAAAAAAAAAAAAAAACwAAAAAEAAQAAADNhi63BMgyinFAy0HC3Xj2EJoIEOM32WeaSeeqFK+say+2azUi+5ttx/QJeQIjshkcsBsOp/MBAA7")
self._iconClose = PhotoImage(data="R0lGODlhEAAQAKIAAP///9TQyICAgEBAQAAAAAAAAAAAAAAAACwAAAAAEAAQAAADMxi63BMgyinFAy0HC3XjmLeA4ngpRKoSZoeuDLmo38mwtVvKu93rIo5gSCwWB8ikcolMAAA7")
max_height_of_icon = max(self._iconOpen.height(), self._iconClose.height())
max_width_of_icon = max(self._iconOpen.width(), self._iconClose.width())
containerFrame_pady = (max_height_of_icon//2) +1
self._inner_height = inner_height
self._inner_width = inner_width
self._containerFrame = Frame(self, borderwidth=borderwidth, width=inner_width, height=inner_height, relief=RIDGE, background=background)
self._containerFrame.pack(expand=True, fill=X, pady=containerFrame_pady)
self.interior = Frame(self._containerFrame, background=background)
self._collapseButton = Label(self, borderwidth=0, image=self._iconOpen, relief=RAISED)
self._collapseButton.place(in_= self._containerFrame, x=button_padx, y=-(max_height_of_icon//2), anchor=N+W, bordermode="ignore")
self._collapseButton.bind("<Button-1>", lambda event: self.toggle())
self._captionLabel = Label(self, anchor=W, borderwidth=1, text=text)
if caption_font is not None:
self._captionLabel.configure(font=caption_font)
x = caption_separation + button_padx + max_width_of_icon
y = -(self._captionLabel.winfo_reqheight()//2)
self._captionLabel.place(in_= self._containerFrame, x=x, y=y, anchor=N+W, bordermode="ignore")
def update_width(self, width=None):
# Update could be devil
# http://wiki.tcl.tk/1255
self.after(0, lambda width=width:self._update_width(width))
def _update_width(self, width):
self.update()
if width is None:
width=self.interior.winfo_reqwidth()
if isinstance(self._ipady, (list, tuple)):
width += self._ipady[0] + self._ipady[1]
else:
width += 2*self._ipady
width = max(self._inner_width, width)
self._containerFrame.configure(width=width)
def open(self):
self._collapseButton.configure(image=self._iconClose)
self._containerFrame.configure(height=self.interior.winfo_reqheight())
self.interior.pack(expand=True, fill=X, padx=self._ipadx, pady =self._ipady)
self._is_opened = True
def close(self):
self.interior.pack_forget()
self._containerFrame.configure(height=self._inner_height)
self._collapseButton.configure(image=self._iconOpen)
self._is_opened = False
def toggle(self):
if self._is_opened:
self.close()
else:
self.open()
if __name__ == "__main__":
try:
from Tkinter import Tk, Button
except ImportError:
from tkinter import Tk, Button
root = Tk()
root.wm_geometry("400x300+0+0")
cf1 = CollapsibleFrame(root, text ="Frame1", ipadx=6)
cf1.pack()
for i in range(5):
Button(cf1.interior, text="button %s"%i).pack()
cf1.update_width()
root.mainloop()
Diff to Previous Revision
--- revision 2 2017-03-04 00:36:02
+++ revision 3 2017-03-04 00:37:28
@@ -1,3 +1,10 @@
+# Author: Miguel Martinez Lopez
+#
+# Version: 0.1
+# Uncomment the next line to see my email
+# print("Author's email: %s"%"61706c69636163696f6e616d656469646140676d61696c2e636f6d".decode("hex"))
+
+
try:
from Tkinter import PhotoImage, Frame, Label
from Tkconstants import *