2022년 10월 9일 일요일

[python] wxPython demo

 


import wx
 
class FileDrop(wx.FileDropTarget):
    def __init__(self, window):
        wx.FileDropTarget.__init__(self)
        self.window = window
    def OnDropFiles(self, x, y, filenames):
        self.window.drop_handle(filenames)
        return True

class VBox(wx.Panel):
    def __init__(self,parent):
        super().__init__( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        self.box = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(self.box)
    def Add(self,ctrl,border=5,expand=False,fill=False,bottom=False):
        flag = wx.ALIGN_BOTTOM if bottom else 0
        flag |= wx.EXPAND if expand else 0
        flag |= wx.ALL if border else 0
        self.box.Add( ctrl, 1 if fill else 0, flag, border )
        return ctrl
        
class HBox(wx.Panel):
    def __init__(self, parent):
        super().__init__( parent, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        self.box = wx.BoxSizer(wx.HORIZONTAL)
        self.SetSizer(self.box)
    def Add(self,ctrl,border=5,expand=False,fill=False,right=False):
        flag = wx.ALIGN_CENTER_VERTICAL
        flag |= wx.ALIGN_RIGHT if right else 0
        flag |= wx.EXPAND if expand else 0
        flag |= wx.ALL if border else 0
        self.box.Add( ctrl, 1 if fill else 0, flag, border )
        return ctrl
        
class Label(wx.StaticText):
    def __init__(self, parent, label):
        super().__init__( parent, wx.ID_ANY, label, wx.DefaultPosition, wx.DefaultSize, 0 )
        self.Wrap(-1)

class Button(wx.Button):
    def __init__(self, parent, label, handler=None):
        super().__init__( parent, wx.ID_ANY, label, wx.DefaultPosition, wx.DefaultSize, 0 )
        if handler: self.Bind(wx.EVT_BUTTON, handler)

class TextField(wx.TextCtrl):
    def __init__(self, parent, label=wx.EmptyString, handler=None):
        super().__init__( parent, wx.ID_ANY, label, wx.DefaultPosition, wx.DefaultSize, 0 )
        if handler: pass

class Text(wx.TextCtrl):
    def __init__(self, parent, label=wx.EmptyString, handler=None):
        super().__init__( parent, wx.ID_ANY, label, wx.DefaultPosition, wx.DefaultSize,
            wx.TE_MULTILINE|wx.TE_WORDWRAP )

class WxWin(wx.Frame):
    def __init__(self,title="Untitled",width=600,height=400):
        self.app = wx.App(False)
        super().__init__( None, id = wx.ID_ANY, title = title, 
            pos = wx.DefaultPosition, 
            size = wx.Size( width, height ), 
            style = wx.CAPTION|wx.CLOSE_BOX|wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX|wx.SYSTEM_MENU|wx.TAB_TRAVERSAL )
        self.vbox = wx.BoxSizer( wx.VERTICAL )
    def VBox(self):
        panel = wx.Panel( wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        box = wx.BoxSizer( wx.VERTICAL )
        return (panel, box)
    def HBox(self):
        panel = wx.Panel( wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
        box = wx.BoxSizer( wx.HORIZONTAL )
        return (panel, box)
    def Add(self,panel,expand=False, fill=False):
        flag = wx.ALL
        flag |= wx.EXPAND if expand else 0
        self.vbox.Add( panel, 1 if fill else 0, flag, 0 )
    def Run(self):
        self.SetSizer( self.vbox )
        self.Layout()
        self.Centre( wx.BOTH )
        self.Show(True)
        self.app.MainLoop()
        
if __name__ == "__main__":
    def open_handler(event):
        print(event)
    def get_output_panel(parent):
        hbox = HBox(parent)
        hbox.Add( Label(hbox, "Ouput:" ) )
        hbox.Add( TextField(hbox), fill=True )
        hbox.Add( Button(hbox, "Open", open_handler) )
        return hbox
    def get_main_panel(parent):
        vbox = VBox(win)
        vbox.Add( Text(vbox), expand=True, fill=True )
        return vbox
    win = WxWin("WxWidget Demo", 400, 300)
    out_panel = get_output_panel(win)
    main_panel = get_main_panel(win)
    win.Add(out_panel, expand=True)
    win.Add(main_panel, expand=True, fill=True)
    win.Run()
    
    

2022년 10월 7일 금요일

[python] tkinter wrapper example

 Tkinter Wrapper Example


from tkinter import *
from tkinter.ttk import *
from tkinter.font import *
from tkinter.simpledialog import *
from tkinter.filedialog import *
from tkinter.messagebox import *
from tkinter.scrolledtext import ScrolledText
import tkinterDnD
from PIL import ImageTk, Image

#
# Libraries
#

class PilImage():
    def __init__(self, image):
        if type(image) == str: self.image = Image.open(image)
        else:
            self.image = Image.new('P', image)
            newData = [(255, 255, 255, 0) for i in range(len(self.image.getdata()))]
            self.image.putdata(newData)
    def resize(self,size):
        width = size[0]
        radio = width / self.image.width
        height = int(radio * self.image.height)
        if height > size[1]:
            height = size[1]
            radio = height / self.image.height
            width = int(radio * self.image.width)
        self.image = self.image.resize((width,height), resample=0)
        return self

#
# Controls
#

class ScrolledList(Frame):
    def __init__(self,parent,events={}):
        super().__init__(parent)
        frame = self
        self.listbox = Listbox(frame)
        self.listbox.config(selectmode='extended')
        self.listbox.config()#width=w,height=h)
        self.listbox.pack(side=LEFT,fill=Y,expand=True)
        if events.get('select'): self.listbox.bind('<<ListboxSelect>>', events['select'])
        scroll = Scrollbar(frame,orient=VERTICAL,command=self.listbox.yview)
        scroll.pack( side=RIGHT, fill=Y )
        self.listbox.config( yscrollcommand = scroll.set)
    def Count(self): return self.listbox.size()
    def AddItem(self,value,index=END): self.listbox.insert(index,value)
    def DeleteItem(self,index): self.listbox.delete(index)
    def SelectedIndex(self): return self.listbox.curselection()
    #def SelectedItem(self): return self.listbox.get(self.listbox.curselection())

class Text(ScrolledText):
    def __init__(self,parent): super().__init__(parent)
    def Clear(self): self.delete("1.0",END); return self
    def AddText(self,value): self.insert(END,value); return self
    def SetText(self,value): self.Clear(); self.AddText(value); return self
    def GetText(self): return self.get("1.0",END)

class TextField(Entry):
    def __init__(self,parent,events={}):
        super().__init__(parent)
        if events.get('enter'): self.bind("<Return>",events['enter'])
    def Clear(self): self.delete(0,END); return self
    def AddText(self,value): self.insert(END,value); return self
    def SetText(self,value): self.Clear(); self.AddText(value); return self
    def GetText(self): return self.get(0,END)

#
# Containers
#

def Splitter(parent,layout,panels,params={'orient' : HORIZONTAL }):
    splitter = PanedWindow(parent,params)
    for panel in panels: splitter.add(panel(splitter))
    splitter.pack(layout)
    return splitter

def Tab(parent,layout,labels,panels):
    tab = Notebook(parent)
    for index,panel in enumerate(panels): tab.add(panel(tab),text=labels[index])
    tab.pack(layout)
    return tab

def Box(parent,layout,panels):
    frame = Frame(parent)
    for panel in panels: panel(frame)
    frame.pack(layout)
    return frame

#
# Layouts
#

def Control(ctrl,layout,params={},events={}):
    control = {}
    control['ctrl'] = ctrl
    control['layout'] = layout
    control['params'] = params
    control['events'] = events
    return control

def Panel(parent,layout,controls):
    def GetControl(parent,ctrl,handler=None):
        params = ctrl['params']
        events = ctrl['events']
        if   ctrl['ctrl'] == 'List':   c = ScrolledList(parent,events)
        elif ctrl['ctrl'] == 'Text':   c = Text(parent)
        elif ctrl['ctrl'] == 'TextField':   c = TextField(parent,events)
        elif ctrl['ctrl'] == 'Button': c = Button(parent) #,params)
        elif ctrl['ctrl'] == 'Label':  c = Label(parent) #,params)
        else: return None
        if events.get('drop'): c.register_drop_target("*"); c.bind("<<Drop>>",events['drop'])
        c.config(params)
        c.pack(ctrl.get('layout'))
        return c
    widgets = []
    f = Frame(parent)
    for ctrl in controls: widgets.append(GetControl(f,ctrl))
    f.pack(layout)
    return (f, widgets)

#
# Application
#

page_list = []
image_file = None
image_label = None
list_box = None
text_edit = None
output_edit = None

def MakeOutputFrame(parent):
    global output_edit
    ctrl_1 = Control('Label',
        layout = { 'side' : LEFT, 'padx' : 10 },
        params = { 'text' : 'Output', } )
    ctrl_2 = Control('TextField',
        layout = { 'side' : LEFT, 'expand' : True, 'fill' : X },
        #params = { 'text' : 'Open',  },
        events = { 'enter' : make_handler2 } )
    ctrl_3 = Control('Button',
        layout = { 'side' : LEFT, 'padx' : 10},
        params = { 'text' : 'Open', 'command' : open_handler })
    (frame, widgets) = Panel(parent,
        layout = { 'side' : TOP, 'fill' : X},
        controls = (ctrl_1, ctrl_2, ctrl_3) )
    output_edit = widgets[1]
    return frame

def MakeTitleFrame(parent):
    global output_edit
    ctrl_1 = Control('Label',
        layout = { 'side' : LEFT, 'padx' : 10 },
        params = { 'text' : 'Title', } )
    ctrl_2 = Control('TextField',
        layout = { 'side' : LEFT, 'expand' : True, 'fill' : X, 'padx' : 10 },
        events = { 'enter' : make_handler2 } )
    (frame, widgets) = Panel(parent,
        layout = { 'side' : TOP, 'fill' : X, 'pady' : 5},
        controls = (ctrl_1, ctrl_2, ) )
    output_edit = widgets[1]
    return frame
    
def MakeSplitter(parent):
    def MakeListFrame(parent):
        def MakeListBox(parent):
            global list_box
            ctrl_1 = Control('List',
                layout = { 'side' : TOP , 'expand' : True , 'fill' : BOTH},
                events = {'select' : list_selected} )
            (frame, widgets) = Panel(parent,
                layout = { 'side' : TOP, 'expand' : True, 'fill' : BOTH},
                controls = (ctrl_1, ))
            list_box = widgets[0]
            return frame
        def MakeButtonBox(parent):
            ctrl_2 = Control('Button',
                layout = { 'side' : RIGHT, 'padx' : 5 },
                params = { 'text' : 'Make', 'command' : make_handler })
            ctrl_3 = Control('Button',
                layout = { 'side' : RIGHT, },
                params = { 'text' : 'Delete', 'command' : delete_handler })
            (frame, widgets) = Panel(parent,
                layout = { 'side' : BOTTOM, 'fill' : X, 'pady' : 5,'padx' : 5 },
                controls = (ctrl_2, ctrl_3))
            return frame
        return Box( parent,
            layout = { 'side' : TOP, 'expand' : True, 'fill' : BOTH, 'pady' : 5,'padx' : 10 },
            panels = (MakeListBox, MakeButtonBox, ))

    def MakeImageFrame(parent):
        def MakePageBox(parent):
            global image_label, text_edit
            ctrl_1 = Control('Label',
                layout = { 'expand' : True , 'fill' : BOTH},
                params = {'bg' : 'white'},
                events = {'drop' : image_drop})
            ctrl_2 = Control('Text',
                layout = { 'side' : BOTTOM, 'anchor' : S, 'fill' : BOTH,'pady' : 5},
                params = { 'height' : 3 })
            (frame, widgets) = Panel(parent,
                layout = { 'side' : BOTTOM, 'expand' : True, 'fill' : BOTH },
                controls = (ctrl_2, ctrl_1, ))
            image_label = widgets[1]
            text_edit = widgets[0]
            return frame
        def MakeButtonBox(parent):
            ctrl_3 = Control('Button',
                layout = { 'side' : RIGHT, 'padx' : 5 },
                params = { 'text' : 'Add', 'command' : add_handler })
            ctrl_4 = Control('Button',
                layout = { 'side' : RIGHT },
                params = { 'text' : 'Update', 'command' : update_handler })
            ctrl_5 = Control('TextField',
                layout = { 'side' : RIGHT, 'expand' : True, 'fill' : X, 'padx' : 10  },
                #params = { 'text' : 'Open',  }, 
                )
            ctrl_6 = Control('Label',
                layout = { 'side' : RIGHT },
                params = { 'text' : 'Outline', } )
            (frame, widgets) = Panel(parent,
                layout = { 'side' : BOTTOM, 'fill' : X, 'pady' : 5,'padx' : 5 },
                controls = (ctrl_3, ctrl_4, ctrl_5, ctrl_6))
            return frame
            
        return Box( parent,
            layout = { 'side' : TOP, 'expand' : True, 'fill' : BOTH, 'pady' : 10,'padx' : 10 },
            panels = ( MakeButtonBox, MakePageBox,  ))


    return Splitter( parent,
        layout = { 'side' : TOP, 'expand' : True, 'fill' : BOTH, 'pady' : 10,'padx' : 10 },
        params = { 'orient' : HORIZONTAL },
        panels = ( MakeListFrame, MakeImageFrame ) )

def open_handler():
    #text = askdirectory()
    text = asksaveasfilename(initialdir="/", title="Select file",
                                          filetypes=(("PDF files", "*.pdf"),
                                          ("all files", "*.*")))
    if len(text) > 0:
        output_edit.SetText(text)

def list_selected(ev):
    global text_edit, image_label, page_list, page_item, image_thumb, image_file
    index = ev.widget.curselection()[0]
    image_label.config(image = page_list[index][1])
    text_edit.SetText(page_list[index][2])
    image_thumb = page_list[index][1]
    image_file = page_list[index][0]
    
def image_drop(ev):
    global image_label, image_thumb, image_file, text_edit
    im = PilImage(ev.data).resize((image_label.winfo_width(), image_label.winfo_height()))
    image_thumb = ImageTk.PhotoImage(im.image) #Image.open("Lenna.png")
    image_label.config(image = image_thumb); #image_label.image = image_thumb
    image_file = ev.data

def add_handler():
    global image_label, image_thumb, image_file, text_edit, list_box, page_list
    page_item = [image_file, image_thumb, text_edit.GetText()]
    page_list.append( page_item ); print(page_list)
    list_box.AddItem("Page " + str(len(page_list)))
    im = PilImage((image_label.winfo_width(), image_label.winfo_height()))
    image_label.config( image = ImageTk.PhotoImage(im.image) )
    text_edit.Clear()

def update_handler():
    global image_label, image_thumb, image_file, text_edit, list_box, page_list
    index = list_box.SelectedIndex()
    if index[0] >= 0:
        page_item = [image_file, image_thumb, text_edit.GetText()]
        page_list[index[0]] = page_item; print(page_list)
        im = PilImage((image_label.winfo_width(), image_label.winfo_height()))
        image_label.config( image = ImageTk.PhotoImage(im.image) )
        text_edit.Clear()

def delete_handler():
    index = list_box.SelectedIndex()
    if index[0] >= 0:
        del page_list[index[0]]
        list_box.DeleteItem(list_box.Count()-1)

def make_handler2(ev): make_handler()
def make_handler():
    import pdf
    import json
    data = {}
    data['title'] = 'Album'
    data['pages'] = []
    for page in page_list:
        data['pages'].append( { \
            'pictures' : [ page[0] ], \
            'comment' : page[2] \
            } )
    pdf.make_pdf(json.dumps(data),'tkalbum.pdf')
    showinfo( title="알림", message="생성되었습니다" )

if __name__ == "__main__":
    root = tkinterDnD.Tk()
    root.title("Album")
    root.geometry("600x400")
    root.resizable(False,False)

    Box( root,
        layout = { 'side' : TOP, 'expand' : True, 'fill' : BOTH, 'pady' : 10,'padx' : 10 },
        panels = (MakeOutputFrame, MakeTitleFrame, MakeSplitter, ))

    '''Tab( root,
        layout = { 'side' : TOP, 'expand' : True, 'fill' : BOTH, 'pady' : 10,'padx' : 10 },
        labels = ( 'Tab1', 'Tab2' ),
        panels = ( MakeListFrame, MakeImageFrame ) )'''

    root.mainloop()

[python] tkinter example 2


Tkinter example 2


from tkinter import *
from tkinter.ttk import *
from tkinter.font import *
from tkinter.simpledialog import *
from tkinter.messagebox import *
from tkinter.scrolledtext import ScrolledText
import tkinterDnD
from PIL import ImageTk, Image

class TkTab(Notebook):
    def __init__(self,parent): super().__init__(parent)
    def AddItem(self,node,text): self.add(node,text=text)

class TkSplitter(PanedWindow):
    def __init__(self,parent,orient=HORIZONTAL): super().__init__(parent,orient=orient)
    def AddItem(self,node): self.add(node)

class TkLabel(Label):
    def __init__(self,parent,text=""): super().__init__(parent,text=text)

class TkButton(Button):
    def __init__(self,parent,text="",handler=None,width=None): super().__init__(parent,text=text,command=handler,width=width)

class TkText(ScrolledText):
    def __init__(self,parent,values=None,handler=None): super().__init__(parent)
    def Clear(self): self.delete("1.0",END); return self
    def AddText(self,value): self.insert(END,value); return self
    def SetText(self,value): self.Clear(); self.AddText(value); return self
    def GetText(self): return self.get("1.0",END)
    
class TkScrolledList(Frame):
    def __init__(self,parent,handler=None):
        super().__init__(parent)
        frame = self
        self.listbox = Listbox(frame)
        self.listbox.config(selectmode='extended')
        self.listbox.config()#width=w,height=h)
        self.listbox.pack(side=LEFT,fill=Y,expand=True)
        if handler: self.listbox.bind('<<ListboxSelect>>', handler)
        scroll = Scrollbar(frame,orient=VERTICAL,command=self.listbox.yview)
        scroll.pack( side=RIGHT, fill=Y )
        self.listbox.config( yscrollcommand = scroll.set)
    def AddItem(self,value,index=END): self.listbox.insert(index,value)

class PilImage():
    def __init__(self, image): 
        if type(image) == str: self.image = Image.open(image)
        else:
            self.image = Image.new('P', image)
            newData = [(255, 255, 255, 0) for i in range(len(self.image.getdata()))]
            self.image.putdata(newData)
    def resize(self,size): 
        width = size[0]
        radio = width / self.image.width
        height = int(radio * self.image.height)
        if height > size[1]: 
            height = size[1]
            radio = height / self.image.height
            width = int(radio * self.image.width)
        self.image = self.image.resize((width,height), resample=0)
        return self
            
def ListFrame(parent):
    global listbox
    frame = Frame(parent)
    sl = TkScrolledList(frame, list_selected)
    sl.pack(side=TOP,expand=True,fill=Y)
    makebtn = TkButton(frame, "만들기",make_handler,width=6)
    makebtn.pack(side=TOP,anchor=E,pady=10,padx=20)
    listbox = sl.listbox
    return frame

def ImageFrame(parent):
    global image_label, text_edit
    frame = Frame(parent)
    addbtn = TkButton(frame, "추가",add_handler,width=6)
    addbtn.pack(side=BOTTOM,anchor=E,pady=5,padx=20)
    text_edit = TkText(frame)
    text_edit.config(height = 3)
    text_edit.pack(side=BOTTOM,anchor=S,fill=BOTH,pady=5)
    image_label = TkLabel(frame)
    image_label.config(bg='lightgrey')
    image_label.register_drop_target("*")
    image_label.bind("<<Drop>>",image_drop)
    image_label.pack(expand=True,fill=BOTH)
    return frame

def list_selected(ev): 
    global text_edit, image_label, page_list, page_item
    index = ev.widget.curselection()[0]
    image_label.config(image = page_list[index][1])
    text_edit.SetText(page_list[index][2])
    
def image_drop(ev): 
    global image_label, image_thumb, image_file, text_edit
    im = PilImage(ev.data).resize((image_label.winfo_width(), image_label.winfo_height()))
    image_thumb = ImageTk.PhotoImage(im.image) #Image.open("Lenna.png")
    image_label.config(image = image_thumb); #image_label.image = image_thumb   
    image_file = ev.data

def add_handler(): 
    global image_label, image_thumb, image_file, text_edit, listbox, page_list
    page_item = [image_file, image_thumb, text_edit.GetText()]
    page_list.append( page_item ); print(page_list)
    listbox.insert(END,"Page " + str(len(page_list)))
    im = PilImage((image_label.winfo_width(), image_label.winfo_height()))
    image_label.config( image = ImageTk.PhotoImage(im.image) )   
    text_edit.Clear()

def make_handler(): 
    import pdf
    import json
    data = {}
    data['title'] = 'Album' 
    data['pages'] = []
    for page in page_list:
        data['pages'].append( { \
            'pictures' : [ page[0] ], \
            'comment' : page[2] \
            } )
    pdf.make_pdf(json.dumps(data),'tkalbum.pdf')
    showinfo( title="알림", message="생성되었습니다" )

page_list = []
image_file = None
image_label = None
listbox = None
text_edit = None
    
if __name__ == "__main__":
    root= tkinterDnD.Tk()
    root.title("Album")
    root.geometry("400x300")
    root.resizable(False,False)

    splitter = TkSplitter(root)
    splitter.AddItem(ListFrame(splitter))
    splitter.AddItem(ImageFrame(splitter))
    splitter.pack(side=TOP,expand=True,fill=BOTH,pady=10,padx=10)
    root.mainloop() 

2022년 7월 24일 일요일

[python] tkinter 기본

 tkinter 기본


  




import os
from tkinter import *
from tkinter.ttk import *
from tkinter.font import *
from tkinter.simpledialog import *
from tkinter.messagebox import *
from tkinter.scrolledtext import ScrolledText

SIZE = 'size'
FONT = 'font'
WEIGHT = 'weight'

class packer():
    def side_top(self): self.pack( side = TOP ); return self
    def side_bottom(self): self.pack( side = BOTTOM ); return self
    def side_left(self): self.pack( side = LEFT ); return self
    def side_right(self): self.pack( side = RIGHT ); return self
    def fill_both(self): self.pack( fill = BOTH ); return self
    def fill(self): self.pack( fill = BOTH ); return self
    def fill_x(self): self.pack( fill = X ); return self
    def fill_y(self): self.pack( fill = Y ); return self
    def expand(self): self.pack( expand = YES ); return self
    def anchor_n(self): self.pack( anchor = N ); return self
    def anchor_ne(self): self.pack( anchor = NE ); return self
    def anchor_e(self): self.pack( anchor = E ); return self
    def anchor_se(self): self.pack( anchor = SE ); return self
    def anchor_s(self): self.pack( anchor = S ); return self
    def anchor_sw(self): self.pack( anchor = SW ); return self
    def anchor_w(self): self.pack( anchor = W ); return self
    def anchor_nw(self): self.pack( anchor = NW ); return self

class grider():
    def set_grid(self,r,c): self.grid(row=r,column=c); return self
    def sticky_n(self): self.grid( sticky = N ); return self
    def sticky_ne(self): self.grid( sticky = NE ); return self
    def sticky_e(self): self.grid( sticky = E ); return self
    def sticky_se(self): self.grid( sticky = SE ); return self
    def sticky_s(self): self.grid( sticky = S ); return self
    def sticky_sw(self): self.grid( sticky = SW ); return self
    def sticky_w(self): self.grid( sticky = W ); return self
    def sticky_nw(self): self.grid( sticky = NW ); return self
    def sticky_ns(self): self.grid( sticky = NS ); return self
    def sticky_ew(self): self.grid( sticky = EW ); return self
    def sticky_nsew(self): self.grid( sticky = NSEW ); return self
    def weightx(self,c,value): self.grid_columnconfigure(c,weight=value); return self
    def weighty(self,r,value): self.grid_rowconfigure(r,weight=value); return self
    def weight(self,r,c,value): self.weightx(c,value); self.weighty(r,value); return self

class widget(packer,grider):
    def padx(self,value): self.config( padx = value ); return self;
    def pady(self,value): self.config( pady = value ); return self;
    def pad(self,value): self.config( padx = value, pady = value ); return self;
    def ipad(self,value): self.config( ipadx = value, ipady = value ); return self;
    def text(self,value): self.config(text = value); return self
    def background(self,value): self.config(background = value); return self
    def foreground(self,value): self.config(foreground = value); return self
    def width(self,value): self.config(width = value); return self
    def fontsize(self,value): self.font[SIZE] = value;  self.config( font = self.font ); return self
    def fontbold(self): self.font[WEIGHT] = BOLD; self.config( font = self.font ); return self
    def border_flat(self,value): self.config( borderwidth=value, relief=FLAT ); return self
    def border_raised(self,value): self.config( borderwidth=value, relief=RAISED ); return self
    def border_sunken(self,value): self.config( borderwidth=value, relief=SUNKEN ); return self
    def border_groove(self,value): self.config( borderwidth=value, relief=GROOVE ); return self
    def border_RIDGE(self,value): self.config( borderwidth=value, relief=RIDGE ); return self

class window(Tk):
    def __init__(self):
        super().__init__()

class tab(Notebook,widget):
    def __init__(self,parent):
        super().__init__(parent)
    def add_item(self,node,text):
        self.add(node,text=text)

class split(PanedWindow,widget):
    def __init__(self,parent,orient=HORIZONTAL):
        super().__init__(parent,orient=orient)
    def add_item(self,node):
        self.add(node)

class hbox(Frame,widget):
    def __init__(self,parent): super().__init__(parent)
    def add_hbox(self): return hbox(self).side_left().fill_both()
    def add_vbox(self): return vbox(self).side_left().fill_both()
    def add_grid(self): return grid(self).side_left().fill_both()
    def add_label(self,value): return label(self).text(value).side_left()
    def add_button(self,value,handler=None): return button(self,value,handler).side_left()
    def add_entry(self,value,handler=None): return entry(self,value,handler).side_left()
    def add_list(self,handler=None): return list(self,handler).side_left()
    def add_combo(self,values=None,handler=None): return combo(self,values=values,handler=handler).side_left()
    def add_text(self): return text(self).side_left()
    def add_table(self,columns=None,handler=None): return table(self,columns=columns,handler=handler).side_left()

class vbox(Frame,widget):
    def __init__(self,parent): super().__init__(parent)
    def add_hbox(self): return hbox(self).side_top().fill_both()
    def add_vbox(self): return vbox(self).side_top().fill_both()
    def add_grid(self): return grid(self).side_top().fill_both()
    def add_label(self,value): return label(self,value).side_top()
    def add_button(self,value,handler=None): return button(self,value,handler).side_top()
    def add_entry(self,value,handler=None): return entry(self,value,handler).side_top()
    def add_list(self,handler=None): return list(self,handler).side_top()
    def add_combo(self,values=None,handler=None): return combo(self,values=values,handler=handler).side_top()
    def add_text(self): return text(self).side_top()
    def add_table(self,columns=None,handler=None): return table(self,columns=columns,handler=handler).side_top()

class grid(Frame,widget):
    def __init__(self,parent): super().__init__(parent)
    def add_hbox(self,r,c): return hbox(self).set_grid(r,c)
    def add_vbox(self,r,c): return vbox(self).set_grid(r,c)
    def add_grid(self,r,c): return grid(self).set_grid(r,c)
    def add_label(self,value,r,c): return label(self).set_grid(r,c).text(value).sticky_nsew()

class label(Label,widget):
    def __init__(self,parent,text=""):
        super().__init__(parent,text=text)
        self.font = Font()

class button(Button,widget):
    def __init__(self,parent,text="",handler=None):
        super().__init__(parent,text=text,command=handler)
        self.font = Font()

class entry(Entry,widget):
    def __init__(self,parent,text="",handler=None):
        super().__init__(parent,text=text)
        self.var = StringVar()
        self.var.set(text)
        self.font = Font()
        self.config( textvariable = self.var )
        if handler: self.bind( '<Return>', handler )
    def get_text(self): return self.var.get()
    def set_text(self,value): self.var.set(value)

class text(ScrolledText,widget):
    def __init__(self,parent,values=None,handler=None):
        super(text,self).__init__(parent)

class combo(Combobox,widget):
    def __init__(self,parent,values=None,handler=None):
        super(combo,self).__init__(parent)
        self.var = StringVar()
        self.config( textvariable = self.var )
        self['values'] = values if values else []
        if handler: self.bind('<<ComboboxSelected>>', handler)
        if handler: self.bind('<Return>', handler)
    def set_values(self,values): self['values'] = values; return self
    def get_text(self): return self.var.get()
    def set_text(self,value): self.var.set(value); return self
    def readonly(self,value=True): self['state'] = 'readonly' if value == True else ''; return self

class list(Listbox,widget):
    def __init__(self,parent,handler=None):
        super(list,self).__init__(parent)
        self.config(selectmode='extended')
        self.config(height=0)
        if handler: self.bind('<<ListboxSelect>>', handler)
        scroll = Scrollbar(parent,orient=VERTICAL,command=self.yview)
        scroll.pack( side=RIGHT, fill=Y )
        self.config( yscrollcommand = scroll.set)
    def add(self,value,index=END): self.insert(index,value); return self

class table(Treeview,widget):
    row_color = ( 'white', 'gray')
    def __init__(self,parent,columns=None,handler=None):
        super(table,self).__init__(parent,columns=columns, show='headings')
        if handler: self.bind('<<TreeviewSelect>>', handler)
        scroll = Scrollbar(parent, orient=VERTICAL, command=self.yview)
        #scroll.grid(row=0, column=1, sticky='ns')
        scroll.pack( side=RIGHT, fill=Y )
        self.configure(yscroll=scroll.set)
        self.row_count = 0
        self.tag_configure('white', background='#f0f0f0')
        self.tag_configure('gray', background='#cccccc')
    def column_name(self,name,title): self.heading(name,text=title); return self
    def add_row(self,row,index=END): #, tag='gray'
        self.insert('',END,values=row, tag=table.row_color[self.row_count % 2])
        print(table.row_color[self.row_count % 2])
        self.row_count += 1
    def delete_row(self,item): self.delete(item) #self.tree.selection()[0]

def confirm_dialog(title,message):
    showinfo( title=title, message=message )

if __name__ == '__main__':
    def entry_handler(ev): print(ev.widget.get_text())
    def get_button_handler(v): return lambda : print('Pressed ' + str(v))
    def list_handler(ev): print(ev.widget.curselection())
    def combo_handler(ev): print(ev.widget.get_text())
    def table_handler(ev):
        for selected_item in ev.widget.selection():
            item = ev.widget.item(selected_item)
            record = item['values']
            print(','.join(record))

    def get_layout_frame(parent):
        v = vbox(parent).background("#ff00ff").pad(10).expand().fill_both()
        v.add_label("packer_0").background("#ff0000").pad(10).anchor_w()
        v.add_label("packer_1").background("#ffff00").pad(10).anchor_e()
        h = v.add_hbox().background("#0000ff").pad(10).fill_both()
        h.add_button("packer_2",get_button_handler(2)).background("#ff0000").pad(10)
        h.add_button("packer_3",get_button_handler(3)).background("#ffff00").pad(10)
        h.add_button("packer_4",get_button_handler(4)).background("#00ff00").pad(10).side_right()
        g = v.add_grid().background("#ffff00").expand()
        l = [[None]*3 for i in range(3)]
        g.weightx(0,1).weighty(0,1)
        for r in range(3):
            for c in range(3):
                l[r][c] = g.add_label("grid_{0}{1}".format(r,c),r,c)\
                    .background("#0{0}{1}".format(r*3,c*3))\
                    .foreground("#ffffff").pad(10)
        l[0][0].fontsize(20).fontbold()
        l[2][0].fontsize(30).fontbold()
        l[2][2].fontsize(14).fontbold()
        v.add_entry("Text",entry_handler).fill().fontsize(14).border_flat(5)
        v.add_list(list_handler).add('One').add('Two').add('Three').fill()
        return v

    def get_widget_frame(parent):
        v = vbox(parent).background("#ffff00").pad(10).expand().fill()
        v.add_combo(handler=combo_handler).set_values(('one','two','three')).anchor_w().set_text('four')
        v.add_text().width(40).fill().expand()
        tb = v.add_table(columns=('one','two'),handler=table_handler).fill().expand()
        tb.column_name('one','One')
        tb.column_name('two','Two')
        tb.add_row(('first1','second1'))
        tb.add_row(('first2','second2'))
        tb.add_row(('first3','second3'))
        tb.add_row(('first4','second4'))
        return v

    def get_widget_frame2(parent):
        f=Frame(parent)
        tv=Treeview(f,show='tree')
        ybar=Scrollbar(f,orient=VERTICAL, command=tv.yview)
        tv.configure(yscroll=ybar.set)
        directory='D:/Ebook'
        tv.heading('#0',text='Dir:'+directory,anchor='w')
        path=os.path.abspath(directory)
        node=tv.insert('','end',text=path,open=True)
        def traverse_dir(parent,path):
            for d in os.listdir(path):
                full_path=os.path.join(path,d)
                isdir = os.path.isdir(full_path)
                id=tv.insert(parent,'end',text=d,open=False)
                if isdir:
                    traverse_dir(id,full_path)
        traverse_dir(node,path)
        ybar.pack(side=RIGHT,fill=Y)
        tv.pack(expand=1, fill=BOTH)
        f.pack(expand=1, fill=BOTH)
        return f

    w = window()
    t = tab(w).expand().fill_both()
    s = split(t).expand().fill_both()
    v = get_layout_frame(t)
    v2 = get_widget_frame(t)
    v3 = get_widget_frame2(t)
    s.add_item(v2)
    s.add_item(v3) #label(s,'b').expand().fill_both().background('#ff00ff').border_groove(1))
    s.pack()
    t.add_item(v,'Widgets')
    t.add_item(s,'Split')
    t.pack()
    w.mainloop()


#https://www.pythontutorial.net/tkinter/