import tkinter as tk from tkinter import Text, ttk from tkinter.constants import DISABLED, RIGHT, NORMAL, END import tkinter.filedialog import tkinter.font as tkFont from PIL import Image, ImageTk, ImageFont, ImageDraw from tkinter.colorchooser import askcolor import sys class StdSimulator(): def __init__(self, box) -> None: self.box = box self.stdout = sys.stdout self.stderr = sys.stderr def write(self, msg): self.box.insert(END, msg) self.box.see(END) def flush(self): pass def text_on_image(img, text, pos, size=16, color='#000000'): imgdraw = ImageDraw.Draw(img) imgfont = ImageFont.truetype("msyh.ttc",size=size) textw, texth = imgdraw.textsize(text, font=imgfont) left_top = (pos[0]-int(textw/2), pos[1]-int(texth/2)) imgdraw.text(left_top, text, fill=color, font=imgfont) return img class Loader(tk.Frame): def __init__(self, master=None, conf={}, execution=None, title=None): super().__init__(master) self.master = master self.conf = conf self.execution = execution self.title = title self.pack(fill='both', expand=1) self.resources = {} self.fontStyle = tkFont.Font(size=10, family='微软雅黑') self.fontStyle_anchor = tkFont.Font(size=16) self.create_widgets() # self.font = tk.Font(family='', size=40,weight='',slant='',underline='',overstrike='') if self.title is not None: self.master.title(self.title) def add_resource(self, obj, name): if name in self.resources: print('Name [{0}] Repeated.'.format(name)) print('Current used name:', list(self.resources.keys())) raise ValueError self.resources[name] = obj def add_entry(self, default, width, layout, name, master=None): if master is None: master = self resource = tk.Entry(master, width=width) if type(default) is str: resource.insert(0, default) resource.grid(**layout) self.add_resource(resource, name) def add_label(self, text, layout, name, master=None): if master is None: master = self resource = tk.Label(master, text=text, font=self.fontStyle) resource.grid(**layout) self.add_resource(resource, name) def add_button(self, text, command, layout, size, name, image=None, master=None): if master is None: master = self resource = {} if image is not None: width, height = size image = image.resize((width,height)) if text is not None: image = text_on_image(image, text, (int(width/2), int(height/2)), size=16, color='#000000') img = ImageTk.PhotoImage(image) resource['img'] = img resource['button'] = tk.Button(master, text=text, command=command, borderwidth=0) resource['button'].config(image=img) else: resource['button'] = tk.Button(master, text=text, command=command) resource['button'].grid(**layout) self.add_resource(resource, name) def add_textbox(self, width, layout, name, master=None): if master is None: master = self resource = tk.Text(master, width=width, state=NORMAL) resource.grid(**layout) # vsb = tk.Scrollbar(self, orient="vertical", command=resource.yview) # resource.configure(yscrollcommand=vsb.set) self.add_resource(resource, name) # self.add_resource(vsb, name + '_scroll') def choose_file(self, dst, choose_type='readfile', extension=None, initial_file=None): default_extension = ("所有文件", '.*') args = {"filetypes": []} if extension is not None: args['filetypes'].append(extension) args['filetypes'].append(default_extension) if initial_file is not None: args['initialfile'] = initial_file # print('args:', args) filename = '' if choose_type == 'readfile': filename = tkinter.filedialog.askopenfilename(**args) elif choose_type == 'savefile': filename = tkinter.filedialog.asksaveasfilename(**args) elif choose_type == 'directory': args = { 'initialdir': initial_file } filename = tkinter.filedialog.askdirectory(**args) if filename != '': self.resources[dst].delete(0, 'end') self.resources[dst].insert(0, filename) def choose_color(self, dst): color = askcolor()[0] if color is not None: color = [str(c) for c in color] color = ','.join(color) self.resources[dst].delete(0, 'end') self.resources[dst].insert(0, color) def execute(self): conf = {} for key in self.resources: dtype, name = key.split('_', maxsplit=1) if dtype == 'entry': conf[name] = self.resources[key].get() self.execution(conf) def create_widgets(self): self.rowcount = 0 for key, value in self.conf.items(): name = value['name'] dtype = value['type'] default = value.get('default', '') self.add_label(name, {"row": self.rowcount, "column": 0, "padx": 10, "pady": 5}, name="label_" + key) self.add_entry( default=default, width=None, layout={"row": self.rowcount, "column": 1, "padx": 0, "sticky": "we"}, name='entry_' + key ) destination = 'entry_' + key if dtype in ['readfile', 'savefile', 'directory']: extension = value.get('extension', None) initialfile = default args = { "dst": destination, "choose_type": dtype, "extension": extension, "initial_file": initialfile } self.add_button( text="选择文件", command=lambda args=args:self.choose_file(**args), size=(16, 16), layout={"row":self.rowcount, "column": 2, "padx": 5}, name='{0}_choose'.format(name), image=None ) self.conf[key]['type'] = 'str' elif dtype == 'color': self.add_button( text="选择颜色", command=lambda dst=destination:self.choose_color(dst), size=(16, 16), layout={"row":self.rowcount, "column": 2, "padx": 5}, name='{0}_choose'.format(name), image=None ) self.rowcount += 1 self.add_button( text=" 裁剪 ", command=self.execute, size=(16, 16), layout={"row":self.rowcount, "column": 0, "columnspan": 2, "pady": 5}, name='execute_final' ) self.add_textbox( width=40, layout={"row":0, "column": 3, "rowspan": self.rowcount, "padx": 5, "pady": 0}, name="textbox_log" ) sys.stdout = StdSimulator(self.resources['textbox_log']) sys.stderr = StdSimulator(self.resources['textbox_log']) if __name__ == '__main__': conf = { "input": {"name": "源文件", "type": "readfile", "extension": ("PDF & PPT", ".pdf .pptx")}, "output": {"name": "保存路径", "type": "savefile"}, "background_color": {"name": "背景颜色", "type": "color", "default": "255,255,255"}, "border": {"name": "留白", "type": "str", "default": "0.0"}, "zoom": {"name": "缩放等级", "type": "str", "default": "1.0"}, "thresh": {"name": "阈值", "type": "str", "default": "1.0"}, "split": {"name": "拆分", "type": "str", "default": "false"}, "names": {"name": "页名称", "type": "str"}, "visual": {"name": "显示裁切框", "type": "str", "default": "false"}, "mute": {"name": "显示保存文件", "type": "str", "default": "false"}, } root = tk.Tk() Loader(master=root, conf=conf) root.mainloop()