{"id":23291143,"url":"https://github.com/mleidel/tkauto","last_synced_at":"2026-02-11T10:34:44.177Z","repository":{"id":155144918,"uuid":"321154163","full_name":"MLeidel/TkAuto","owner":"MLeidel","description":"Template and Spreadsheet driven tkinter-design-code generator","archived":false,"fork":false,"pushed_at":"2025-01-18T22:47:08.000Z","size":3168,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-18T23:25:37.106Z","etag":null,"topics":["excel","gui","python3","tkinter"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MLeidel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-13T20:30:55.000Z","updated_at":"2025-01-18T22:47:11.000Z","dependencies_parsed_at":"2025-01-18T23:22:16.825Z","dependency_job_id":"56523016-70d7-4068-9a65-a1ab844a9e6c","html_url":"https://github.com/MLeidel/TkAuto","commit_stats":{"total_commits":64,"total_committers":2,"mean_commits":32.0,"dds":0.421875,"last_synced_commit":"31b1e8ab35264aa363d55eeb1d1dd280ed663559"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MLeidel%2FTkAuto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MLeidel%2FTkAuto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MLeidel%2FTkAuto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MLeidel%2FTkAuto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MLeidel","download_url":"https://codeload.github.com/MLeidel/TkAuto/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238569595,"owners_count":19493912,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["excel","gui","python3","tkinter"],"created_at":"2024-12-20T05:15:27.287Z","updated_at":"2025-10-27T23:30:54.076Z","avatar_url":"https://github.com/MLeidel.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tkauto\n\n## Generates Python/tkinter code for GUIs \n\n__Will generate staight tkinter, ttkthemed, or ttkbootstrap styles__\n\nDesign a grid GUI on paper.  \nThen open the included Excel template to quickly fill in the widget layout.\n\n![drawing](images/mockup.png \"title\")\n\nLaying out tkinter widgets in Excel:\n\n![draw](images/tkauto_layout.png \"title\")\n\n![app final](images/tkauto_app.png \"final app\")\n\ntkauto inputs an xlsx (excel) file and outputs starter code \nfor a Python GUI desktop application. \n\n```bash\n$ python tkauto.py layout.xlsx\n$ python output.py\n\n```\n\nThe Python script will use \ntkinter, ttk, and _ttkthemed_ or _ttkbootstrap_ for the GUI API.\n\n---\n\n## Text Editor App\n\u003eHere is a little more complicated example. Please note that the\nmenu code (blue) was copied from an adjacent sheet as a common\nstarting point for menus.\n\n\n![alttext](images/TkAuto3.png \"title\")\n\nSpreadsheet template:\n- __layout\\_tpl.xlsx__\n\n## Generating the starter script\n\n```python\nusage: tkauto.py [-h] [-x] [-t] [-b] filename\n\ntkauto build Python tkinter GUI\n\npositional arguments:\n  filename    Excel or \"nofile\" for -t option\n\noptions:\n  -h, --help  show this help message and exit\n  -x          Execute with python3 after compile\n  -t          Output just the template - layout=\"nofile\"\n  -b          Use ttkbootstrap template: tkbauto_tpl.py\n\n```\nExample (will create `output.py`):\n\n```bash\n    python3 tkauto.py my_layout.xlsx\n```\n---\n## Output from tkauto.py\n\n```python\n'''\ncode file:\ndate:\ncommants:\n    tkauto generated\n\n'''\nfrom tkinter import *\nfrom tkinter.ttk import *  # defaults all widgets as ttk\nimport os, sys\nfrom tkinter.font import Font\n# import sys\n# import webbrowser\n# import pyperclip\n# from tkinter import filedialog\n# from tkinter import messagebox\n# from tkinter import simpledialog\n# from functools import partial # action_w_arg = partial(self.proc_btns, n)\nfrom ttkthemes import ThemedTk  # ttkthemes is applied to all widgets\n\nclass Application(Frame):\n    ''' main class docstring '''\n    def __init__(self, parent):\n        Frame.__init__(self, parent)\n        self.pack(fill=BOTH, expand=True, padx=4, pady=4)\n        self.create_widgets()\n\n    def create_widgets(self):\n        ''' creates GUI for app '''\n        # expand widget to fill the grid\n        # self.columnconfigure(1, weight=1, pad=100)\n        # self.rowconfigure(1, weight=1, pad=20)\n\n        # myfont = Font(family='Lucida Console', weight = 'bold', size = 20)\n\n        # customize widget style when using ttk...\n        # style = Style()\n        # style.configure(\"TButton\", width=10) # global\n        # style.configure(\"my.TButton\", width=10) # 'style' option\n\n        ''' ONLY OPTIONS FOR 'grid' FUNCTIONS:\n                column  row\n                columnspan  rowspan\n                ipadx and ipady\n                padx and pady\n                sticky=\"nsew\"\n        -------------------------------------------------------- '''\n\n        root.geometry(\"500x400\")\n\n        self.editor = Text(self)\n        self.editor.grid(row=1, column=1, columnspan=2, sticky='nsew')\n\n        \n        # efont = Font(family=\"Helvetica\", size=14)\n        # self.EDITOR.configure(font=efont)\n        # self.EDITOR.config(wrap=\"word\", # wrap=NONE\n        #                    undo=True, # Tk 8.4\n        #                    width=50,\n        #                    height=12,\n        #                    insertbackground='#000',   # cursor color\n        #                    tabs=(efont.measure(' ' * 4),))\n        # self.EDITOR.focus()\n        ## basic handler commands #\n        # .get(\"1.0\", END)\n        # .delete(\"1.0\", END)\n        # .insert(\"1.0\", \"New text content ...\")\n        \n\n        self.scr = Scrollbar(self, orient=VERTICAL, command=self.editor.yview)\n        self.scr.grid(row=1, column=3, sticky='nsw')  # use nse\n        self.editor['yscrollcommand'] = self.scr.set\n\n        self.vlbl = StringVar()\n        lblstat = Label(self, text='status…', textvariable=self.vlbl)\n        lblstat.grid(row=3, column=1, columnspan=3, sticky='ew')\n        self.vlbl.set('status…')\n\n        menubar = Menu(root)\n        mn_file = Menu(menubar, tearoff=0)\n        mn_file.add_command(label=\"New\", command=self.mn_file_new, accelerator=\"Ctrl-n\", underline=1)\n        mn_file.add_command(label=\"Open\", command=self.nm_file_open)\n        mn_file.add_command(label=\"Save\", command=self.nm_file_save, accelerator=\"Ctrl-s\", underline=1)\n        mn_file.add_command(label=\"Save-As\", command=self.nm_file_saveas)\n        mn_file.add_separator()\n        mn_file.add_command(label=\"Exit\", command=self.nm_file_exit, accelerator=\"Ctrl-q\")\n        menubar.add_cascade(label=\"File\", menu=mn_file)\n        mn_edit = Menu(menubar, tearoff=0)\n        mn_edit.add_command(label=\"Undo\", command=self.mn_edit_undo, accelerator=\"Ctrl-z\")\n        mn_edit.add_command(label=\"Select All\", command=self.mn_edit_selall, accelerator=\"Ctrl-a\")\n        submenu = Menu(mn_edit, tearoff=False)\n        submenu.add_command(label=\"Copy\", command=self.mn_edit_copy, accelerator=\"Ctrl-c\")\n        submenu.add_command(label=\"Paste\", command=self.mn_edit_paste, accelerator=\"Ctrl-v\")\n        mn_edit.add_cascade(label=\"Clipboard\", menu=submenu, underline=2)\n        menubar.add_cascade(label=\"Edit\", menu=mn_edit)\n        mn_help = Menu(menubar, tearoff=0)\n        mn_help.add_command(label=\"Help Index\", command=self.mn_help_index)\n        mn_help.add_command(label=\"About…\", command=self.mn_help_about)\n        menubar.add_cascade(label=\"Help\", menu=mn_help)\n        root.config(menu=menubar) # display the menu\n\n\n        \n        # from tkinter import filedialog\n        # filename =  filedialog.askopenfilename(initialdir=\"/\",\n        #             title = \"Open file\",\n        #             filetypes = ((\"jpeg files\", \"*.jpg\"),(\"all files\", \"*.*\")))\n        # filename = filedialog.asksaveasfilename(initialdir=\"/\",\n        #             title = \"Save file\",\n        #             filetypes = ((\"jpeg files\", \"*.jpg\"), (\"all files\", \"*.*\")))\n\n        \n        # self.popup_menu = Menu(self, tearoff=0)\n        # self.popup_menu.add_command(label=\"Copy\",\n        #                             command=lambda:self.function(1))\n        # self.popup_menu.add_command(label=\"Paste\",\n        #                             command=lambda:self.function(2))\n        # self.popup_menu.add_separator()\n        # self.popup_menu.add_command(label=\"say bye\", command=exit)\n        # self.txt.bind(\"\u003cButton-3\u003e\", self.do_popup)\n\n    # def do_popup(self,event):\n    #     try:\n    #         self.popup_menu.tk_popup(event.x_root,\n    #                                  event.y_root)\n    #     finally:\n    #         self.popup_menu.grab_release()\n        \n\n        \n    # def clipbrd(self,n):\n    #     if n == 1:  # Copy\n    #         pyperclip.copy(self.txt.selection_get())\n    #     else:\n    #         # n == 2:  # Paste\n    #         inx = self.txt.index(INSERT)\n    #         self.txt.insert(inx, pyperclip.paste())\n        \n\n        \n        # # from tkinter import simpledialog\n        # simpledialog.askfloat(title, prompt)\n        # simpledialog.askinteger(title, prompt)\n        # simpledialog.askstring(title, prompt)\n        # if answer is not None:\n        \n\n    def mn_file_new(self):\n        ''' docstring '''\n\n    def nm_file_open(self):\n        ''' docstring '''\n\n    def nm_file_save(self):\n        ''' docstring '''\n\n    def nm_file_saveas(self):\n        ''' docstring '''\n\n    def nm_file_exit(self):\n        ''' docstring '''\n\n    def mn_edit_undo(self):\n        ''' docstring '''\n\n    def mn_edit_selall(self):\n        ''' docstring '''\n\n    def mn_edit_copy(self):\n        ''' docstring '''\n\n    def mn_edit_paste(self):\n        ''' docstring '''\n\n    def mn_help_index(self):\n        ''' docstring '''\n\n    def mn_help_about(self):\n        ''' docstring '''\n\n\n    # def eventHandler(self):\n    #     pass\n\n    # def eventHandler(self):\n    #     pass\n\n#\n\n# UNCOMMENT THE FOLLOWING TO SAVE GEOMETRY INFO\n# def save_location(e=None):\n#     ''' executes at WM_DELETE_WINDOW event - see below '''\n#     with open(\"winfo\", \"w\") as fout:\n#         fout.write(root.geometry())\n#     root.destroy()\n\n# ttkthemes\n# 'alt', 'scidsand', 'classic', 'scidblue',\n# 'scidmint', 'scidgreen', 'default', 'scidpink',\n# 'arc', 'scidgrey', 'scidpurple', 'clam', 'smog'\n# 'kroc', 'black', 'clearlooks'\n# 'radiance', 'blue' : https://wiki.tcl-lang.org/page/List+of+ttk+Themes\nroot = ThemedTk(theme=\"scidmint\")\n\n# change working directory to path for this file\np = os.path.realpath(__file__)\nos.chdir(os.path.dirname(p))\n\n# UNCOMMENT THE FOLLOWING TO SAVE GEOMETRY INFO\n# if os.path.isfile(\"winfo\"):\n#     with open(\"winfo\") as f:\n#         lcoor = f.read()\n#     root.geometry(lcoor.strip())\n# else:\n#     root.geometry(\"400x300\") # WxH+left+top\n\n\nroot.title(\"Tkinter Demo\")\n# root.protocol(\"WM_DELETE_WINDOW\", save_location)  # UNCOMMENT TO SAVE GEOMETRY INFO\n# Sizegrip(root).place(rely=1.0, relx=1.0, x=0, y=0, anchor=SE)\n# root.resizable(0, 0) # no resize \u0026 removes maximize button\n# root.minsize(w, h)  # width, height\n# root.maxsize(w, h)\n# root.overrideredirect(True) # removed window decorations\n# root.iconphoto(False, PhotoImage(file='icon.png'))\n# root.attributes(\"-topmost\", True)  # Keep on top of other windows\napp = Application(root)\napp.mainloop()\n\n```\n![alttext](images/editor.png \"output from tkauto\")\n\n## Finished Editor\n\n```python\n'''\ncode file: editor.py\ndate:\ncommants:\n    tkauto generated\n'''\nfrom tkinter import *\nfrom tkinter.ttk import *  # defaults all widgets as ttk\nimport os, sys\nfrom tkinter.font import Font\nfrom tkinter import filedialog\nfrom tkinter import messagebox\nfrom tkinter import simpledialog # NOTE: will NOT be styled !!!\nfrom tkinter.messagebox import showerror\n# from functools import partial # action_w_arg = partial(self.proc_btns, n)\nfrom ttkthemes import ThemedTk  # ttkthemes is applied to all widgets\n\nclass Application(Frame):\n    ''' main class docstring '''\n    def __init__(self, parent):\n        Frame.__init__(self, parent)\n        self.pack(fill=BOTH, expand=True, padx=4, pady=4)\n        self.infile = \"\"\n        self.fontname = \"\"\n        self.create_widgets()\n\n    def create_widgets(self):\n        ''' creates GUI for app '''\n\n        self.editor = Text(self)\n        self.editor.grid(row=1, column=1, columnspan=2, sticky='nsew')\n        # efont = Font(family=\"Andale Mono\", size=12)\n        # self.editor.configure(font=efont)\n        self.editor.config(wrap=NONE    , # wrap=NONE\n                           undo=True, # Tk 8.4\n                           width=50,\n                           height=20,\n                           insertbackground='#000',   # cursor color\n                           )\n        self.editor.focus()\n        \n        self.scr = Scrollbar(self, orient=VERTICAL, command=self.editor.yview)\n        self.scr.grid(row=1, column=3, sticky='nsw')  # use nse\n        self.editor['yscrollcommand'] = self.scr.set\n\n        # get font,size to be used with Text widget\n        if os.path.isfile(\"font\"):\n            with open(\"font\") as f:\n                self.fontname = f.read().strip()\n        else:\n            self.fontname = \"Monospace, 12\"\n        fnt = self.fontname.split(\",\")\n        fnt = [i.strip() for i in fnt]\n        efont = Font(family=fnt[0], size=fnt[1])\n        self.editor.configure(font=efont, tabs=(efont.measure(' ' * 4),))\n\n\n        self.vlbl = StringVar()  # kind of a status bar\n        lblstat = Label(self, text='status…', textvariable=self.vlbl)\n        lblstat.grid(row=3, column=1, columnspan=3, sticky='ew')\n        self.vlbl.set('status…')\n\n        menubar = Menu(root)\n        mn_file = Menu(menubar, tearoff=0)\n        mn_file.add_command(label=\"New\", command=self.mn_file_new, accelerator=\"Ctrl-n\", underline=1)\n        mn_file.add_command(label=\"Open\", command=self.mn_file_open)\n        mn_file.add_command(label=\"Save\", command=self.mn_file_save, accelerator=\"Ctrl-s\", underline=1)\n        mn_file.add_command(label=\"Save-As\", command=self.mn_file_saveas)\n        mn_file.add_separator()\n        mn_file.add_command(label=\"Exit\", command=self.mn_file_exit, accelerator=\"Ctrl-q\")\n        menubar.add_cascade(label=\"File\", menu=mn_file)\n        mn_edit = Menu(menubar, tearoff=0)\n        mn_edit.add_command(label=\"Undo\", command=self.mn_edit_undo, accelerator=\"Ctrl-z\")\n        mn_edit.add_command(label=\"Select All\", command=self.mn_edit_selall, accelerator=\"Ctrl-a\")\n        mn_edit.add_command(label=\"Choose Font\", command=self.mn_edit_font)\n        submenu = Menu(mn_edit, tearoff=False)\n        submenu.add_command(label=\"Copy\", command=self.mn_edit_copy, accelerator=\"Ctrl-c\")\n        submenu.add_command(label=\"Paste\", command=self.mn_edit_paste, accelerator=\"Ctrl-v\")\n        mn_edit.add_cascade(label=\"Clipboard\", menu=submenu, underline=2)\n        menubar.add_cascade(label=\"Edit\", menu=mn_edit)\n        mn_help = Menu(menubar, tearoff=0)\n        mn_help.add_command(label=\"Help Index\", command=self.mn_help_index)\n        mn_help.add_command(label=\"About…\", command=self.mn_help_about)\n        menubar.add_cascade(label=\"Help\", menu=mn_help)\n        root.config(menu=menubar) # display the menu\n\n        self.columnconfigure(1, weight=1, pad=20)\n        self.rowconfigure(1, weight=1, pad=20)\n\n        self.popup_menu = Menu(self, tearoff=0)\n        self.popup_menu.add_command(label=\"Copy\",\n                                    command=lambda:self.clipbrd(1))\n        self.popup_menu.add_command(label=\"Paste\",\n                                    command=lambda:self.clipbrd(2))\n        self.popup_menu.add_separator()\n        self.popup_menu.add_command(label=\"Cancel\",\n                                    command=lambda:self.clipbrd(3))\n        self.editor.bind(\"\u003cButton-3\u003e\", self.do_popup)\n\n        self.editor.bind(\"\u003cEscape\u003e\", self.mn_file_exit)\n        self.editor.bind(\"\u003cControl-q\u003e\", self.mn_file_exit)\n        self.editor.bind(\"\u003cControl-o\u003e\", self.mn_file_open)\n        self.editor.bind(\"\u003cControl-s\u003e\", self.mn_file_save)\n        self.editor.bind(\"\u003cControl-n\u003e\", self.mn_file_new)\n        self.editor.bind(\"\u003cControl-a\u003e\", self.mn_edit_selall)\n\n        # open a file from command - line\n        if (len(sys.argv)) \u003e 1:\n            self.infile = sys.argv[1]\n            f_hand = open(self.infile, \"r\")\n            file_text = f_hand.read()\n            self.editor.insert(1.0, file_text)\n            self.editor.focus()\n            self.editor.mark_set(INSERT, \"1.0\")  # place cursor at 1st character in file\n            self.editor.edit_modified(False)\n            self.vlbl.set(self.infile)\n\n\n    def mn_edit_font(self):\n        if os.path.isfile(\"font\"):\n            with open(\"font\") as f:\n                self.fontname = f.read().strip()\n        self.fontname = simpledialog.askstring(\"Choose Font\", \"Current: \" + self.fontname)\n        if self.fontname is not None:\n            with open(\"font\", \"w\") as f:\n                f.write(self.fontname)\n            fnt = self.fontname.split(\",\")\n            fnt = [i.strip() for i in fnt]\n            efont = Font(family=fnt[0], size=fnt[1])\n            self.editor.configure(font=efont)\n\n\n    def do_popup(self,event):\n        try:\n            self.popup_menu.tk_popup(event.x_root,\n                                     event.y_root)\n        finally:\n            self.popup_menu.grab_release()\n\n\n    def clipbrd(self, n):\n        ''' handle clipboard commands from context menu '''\n        if n == 1:  # Copy\n            if self.editor.tag_ranges(\"sel\"):\n                root.clipboard_clear()  # clear clipboard contents\n                root.clipboard_append(self.editor.selection_get())  # copy to clipboard\n        elif n == 3:  # Cancel\n            inx = self.editor.index(INSERT)\n            self.editor.insert(inx, \"\")\n        else:\n            # n == 2:  # Paste\n            inx = self.editor.index(INSERT)\n            self.editor.insert(inx, root.clipboard_get())  # paste\n\n\n    def mn_file_new(self, event=None):\n        ''' Create a New editor file '''\n        if self.editor.edit_modified():  # modified\n            response = messagebox.askyesnocancel(\n                \"Save?\", \"text was modified.\\nsave changes?\"\n            )\n            if response is True:\n                self.mn_file_save()\n        self.editor.delete(\"1.0\", END)  # clear the Text widget\n        self.editor.mark_set(INSERT, \"1.0\")  # place cursor at 1st character in file\n        self.editor.edit_modified(False)\n        self.editor.focus()\n        self.infile = \"untitled\"\n        self.vlbl.set(self.infile)\n\n\n    def mn_file_open(self, event=None):\n        ''' open a file from the system and put it in the editor '''\n        f_name = filedialog.askopenfilename(\n            filetypes=((\"Text files\", \"*.txt\"), (\"all files\", \"*\"))\n        )\n        if f_name:\n            with open(f_name) as r_hand:\n                file_text = r_hand.read()\n            self.editor.delete(\"1.0\", END)  # clear the Text widget\n            self.editor.insert(\"1.0\", file_text)\n            self.editor.mark_set(INSERT, \"1.0\")  # place cursor at 1st character in file\n            self.editor.edit_modified(False)\n            self.editor.focus()\n            self.infile = f_name\n            self.vlbl.set(self.infile)\n\n\n    def mn_file_save(self, event=None):\n        ''' Save the current editor file '''\n        if self.infile == \"untitled\":\n            self.mn_file_saveas()  # This was a new file\n            return\n        with open(self.infile, \"wb\") as f_hand:\n            file_text = self.editor.get(1.0, \"end-1c\")\n            f_hand.write(bytes(file_text, \"UTF-8\"))\n        self.editor.edit_modified(False)\n\n\n    def mn_file_saveas(self, event=None):\n        ''' Save current editor file as a different filename '''\n        f_name = filedialog.asksaveasfilename(\n            confirmoverwrite=True, initialdir=os.path.dirname(os.path.abspath(__file__))\n        )\n        if f_name:\n            try:\n                with open(f_name, \"w\") as f:\n                    f.write(self.editor.get(\"1.0\", END))\n                self.infile = f_name\n                self.vlbl.set(self.infile)\n                self.editor.edit_modified(False)\n            except:\n                showerror(\"Save File\", \"Failed to save file\\n'%s'\" % f_name)\n            return\n\n\n    def mn_file_exit(self, event=None):\n        ''' Exit the editor App '''\n        if self.editor.edit_modified():  # modified\n            response = messagebox.askyesnocancel(\n                \"Save?\", \"text was modified.\\nsave changes?\"\n            )\n            if response is True:\n                self.mn_file_save()\n        save_location()\n        sys.exit()\n\n\n    def mn_edit_undo(self):\n        ''' docstring '''\n        self.editor.edit_undo()\n\n\n    def mn_edit_selall(self, event=None):\n        ''' docstring '''\n        self.editor.tag_add(\"sel\", \"1.0\", \"end\")\n        return \"break\"\n\n\n    def mn_edit_copy(self, event=None):\n        ''' copy selected from editor '''\n        self.clipbrd(1)\n\n    def mn_edit_paste(self, event=None):\n        ''' paste clipboard to editor '''\n        self.clipbrd(2)\n\n\n    def mn_help_index(self):\n        ''' docstring '''\n        pass\n\n    def mn_help_about(self):\n        ''' docstring '''\n        messagebox.showinfo(\"editor About\", \"Created by me for you.\")\n\n\ndef save_location(e=None):\n    ''' executes at WM_DELETE_WINDOW event - see below '''\n    with open(\"winfo\", \"w\") as fout:\n        fout.write(root.geometry())\n    root.destroy()\n\nroot = ThemedTk(theme=\"scidgreen\")\n\n# change working directory to path for this file\np = os.path.realpath(__file__)\nos.chdir(os.path.dirname(p))\n\nif os.path.isfile(\"winfo\"):\n    with open(\"winfo\") as f:\n        lcoor = f.read()\n    root.geometry(lcoor.strip())\nelse:\n    root.geometry(\"400x300\") # WxH+left+top\n\n\nroot.title(\"Editor Demo\")\nroot.protocol(\"WM_DELETE_WINDOW\", save_location)\nSizegrip(root).place(rely=1.0, relx=1.0, x=0, y=0, anchor=SE)\napp = Application(root)\napp.mainloop()\n\n```\n\n![alttext](images/editor2.png \"finished editor script\")\n\nEND\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmleidel%2Ftkauto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmleidel%2Ftkauto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmleidel%2Ftkauto/lists"}