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()

댓글 없음:

댓글 쓰기