├── LICENSE ├── README.rst ├── cookiecutter.json ├── py3tkinter.png └── {{cookiecutter.repo_name}} └── {{cookiecutter.repo_name}} ├── __init__.py ├── locale ├── de │ └── LC_MESSAGES │ │ ├── messages.mo │ │ └── messages.po └── es │ └── LC_MESSAGES │ ├── messages.mo │ └── messages.po ├── messages.pot └── {{cookiecutter.repo_name}}.py /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Robert Lyon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ================================ 2 | Cookiecutter Py3Tkinter Template 3 | ================================ 4 | 5 | .. image:: https://raw.github.com/audreyr/cookiecutter/aa309b73bdc974788ba265d843a65bb94c2e608e/cookiecutter_medium.png 6 | 7 | A template for command-line utility **cookiecutters** to create a Python 3 package with a Tkinter UI. 8 | 9 | Features 10 | -------- 11 | 12 | * Works on 3.5 (Earlier Python versions untested). 13 | * JSON switches to configure GUI components 14 | * Navigation bar 15 | * Status bar 16 | * Tool bar 17 | * Organized in classes per stack over flow response: http://stackoverflow.com/questions/17466561/best-way-to-structure-a-tkinter-application 18 | 19 | Screenshot 20 | ---------- 21 | 22 | .. image:: py3tkinter.png 23 | -------------------------------------------------------------------------------- /cookiecutter.json: -------------------------------------------------------------------------------- 1 | { 2 | "full_name": "Robert Lyon", 3 | "email": "roblyon00@gmail.com", 4 | "display_name": "Py3 Tkinter", 5 | "repo_name": "py3tinker", 6 | "version": "0.0.1", 7 | "short_description": "Python 3 Tkinter GUI", 8 | "insert_navigation": "y", 9 | "insert_status": "y", 10 | "insert_toolbar": "y", 11 | "language": "english" 12 | } 13 | -------------------------------------------------------------------------------- /py3tkinter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanlyon/cookiecutter-py3tkinter/fa6253434954555afa9ac245ce895d3d76ac70c2/py3tkinter.png -------------------------------------------------------------------------------- /{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | __author__ = '{{cookiecutter.full_name}}' 4 | __email__ = '{{cookiecutter.email}}' 5 | __version__ = '{{cookiecutter.version}}' 6 | 7 | -------------------------------------------------------------------------------- /{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/locale/de/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanlyon/cookiecutter-py3tkinter/fa6253434954555afa9ac245ce895d3d76ac70c2/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/locale/de/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/locale/de/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR ORGANIZATION 3 | # FIRST AUTHOR , YEAR. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: messages\n" 8 | "POT-Creation-Date: 2016-06-16 11:20+PDT\n" 9 | "PO-Revision-Date: 2016-06-16 12:39-0800\n" 10 | "Last-Translator: \n" 11 | "Language-Team: \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | "X-Generator: Poedit 1.6.10\n" 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 18 | "Language: de\n" 19 | 20 | #: {{cookiecutter.repo_name}}.py:37 21 | msgid "OK" 22 | msgstr "OK" 23 | 24 | #: {{cookiecutter.repo_name}}.py:61 25 | msgid "Navigation " 26 | msgstr "Navigation " 27 | 28 | #: {{cookiecutter.repo_name}}.py:74 29 | msgid "List item" 30 | msgstr "Listenpunkt" 31 | 32 | #: {{cookiecutter.repo_name}}.py:88 33 | msgid "Unset status " 34 | msgstr "Unset status " 35 | 36 | #: {{cookiecutter.repo_name}}.py:108 37 | msgid "Tool " 38 | msgstr "Werkzeug " 39 | 40 | #: {{cookiecutter.repo_name}}.py:118 41 | msgid "Toolbar button" 42 | msgstr "Schaltfläche in der Symbolleiste" 43 | 44 | #: {{cookiecutter.repo_name}}.py:118 45 | msgid "pressed" 46 | msgstr "gepresstem" 47 | 48 | #: {{cookiecutter.repo_name}}.py:127 49 | msgid "Template" 50 | msgstr "Vorlage" 51 | 52 | #: {{cookiecutter.repo_name}}.py:155 53 | msgid "New" 54 | msgstr "Neu" 55 | 56 | #: {{cookiecutter.repo_name}}.py:156 57 | msgid "Open" 58 | msgstr "Öffnen" 59 | 60 | #: {{cookiecutter.repo_name}}.py:159 61 | msgid "Exit" 62 | msgstr "Ausgang" 63 | 64 | #: {{cookiecutter.repo_name}}.py:163 {{cookiecutter.repo_name}}.py:170 65 | msgid "Help" 66 | msgstr "Hilfe" 67 | 68 | #: {{cookiecutter.repo_name}}.py:165 {{cookiecutter.repo_name}}.py:195 69 | msgid "About" 70 | msgstr "Von" 71 | 72 | #: {{cookiecutter.repo_name}}.py:169 73 | msgid "File" 74 | msgstr "Feile" 75 | 76 | #: {{cookiecutter.repo_name}}.py:180 77 | msgid "Help not yet created." 78 | msgstr "Hilfe noch nicht erstellt." 79 | 80 | #: {{cookiecutter.repo_name}}.py:188 81 | msgid "No description available" 82 | msgstr "Keine Beschreibung verfügbar" 83 | 84 | #: {{cookiecutter.repo_name}}.py:190 85 | msgid "Author" 86 | msgstr "Autor" 87 | 88 | #: {{cookiecutter.repo_name}}.py:191 89 | msgid "Email" 90 | msgstr "Email" 91 | 92 | #: {{cookiecutter.repo_name}}.py:192 93 | msgid "Version" 94 | msgstr "Version" 95 | 96 | #: {{cookiecutter.repo_name}}.py:193 97 | msgid "GitHub Package" 98 | msgstr "GitHub -Paket" 99 | 100 | #: {{cookiecutter.repo_name}}.py:201 101 | msgid "New button pressed" 102 | msgstr "Neu taste gedrückt" 103 | 104 | #: {{cookiecutter.repo_name}}.py:201 105 | msgid "Not yet implemented" 106 | msgstr "Noch nicht implementiert" 107 | 108 | #: {{cookiecutter.repo_name}}.py:208 109 | msgid "File selected for open: " 110 | msgstr "Datei für Open ausgewählt:" 111 | 112 | #: {{cookiecutter.repo_name}}.py:210 113 | msgid "No file selected" 114 | msgstr "Keine Datei ausgewählt" 115 | 116 | #: {{cookiecutter.repo_name}}.py:252 117 | msgid "Uptime" 118 | msgstr "Betriebszeit" 119 | -------------------------------------------------------------------------------- /{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/locale/es/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanlyon/cookiecutter-py3tkinter/fa6253434954555afa9ac245ce895d3d76ac70c2/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/locale/es/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/locale/es/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR ORGANIZATION 3 | # FIRST AUTHOR , YEAR. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: messages\n" 8 | "POT-Creation-Date: 2016-06-16 11:20+PDT\n" 9 | "PO-Revision-Date: 2016-06-16 12:42-0800\n" 10 | "Last-Translator: \n" 11 | "Language-Team: \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Content-Transfer-Encoding: 8bit\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | "X-Generator: Poedit 1.6.10\n" 17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 18 | "Language: es\n" 19 | 20 | #: {{cookiecutter.repo_name}}.py:37 21 | msgid "OK" 22 | msgstr "De acuerdo" 23 | 24 | #: {{cookiecutter.repo_name}}.py:61 25 | msgid "Navigation " 26 | msgstr "Navegación " 27 | 28 | #: {{cookiecutter.repo_name}}.py:74 29 | msgid "List item" 30 | msgstr "Producto en la lista" 31 | 32 | #: {{cookiecutter.repo_name}}.py:88 33 | msgid "Unset status " 34 | msgstr "estado desarmado " 35 | 36 | #: {{cookiecutter.repo_name}}.py:108 37 | msgid "Tool " 38 | msgstr "Herramienta " 39 | 40 | #: {{cookiecutter.repo_name}}.py:118 41 | msgid "Toolbar button" 42 | msgstr "botón de la barra" 43 | 44 | #: {{cookiecutter.repo_name}}.py:118 45 | msgid "pressed" 46 | msgstr "presionado" 47 | 48 | #: {{cookiecutter.repo_name}}.py:127 49 | msgid "Template" 50 | msgstr "Modelo" 51 | 52 | #: {{cookiecutter.repo_name}}.py:155 53 | msgid "New" 54 | msgstr "Nuevo" 55 | 56 | #: {{cookiecutter.repo_name}}.py:156 57 | msgid "Open" 58 | msgstr "Abierto" 59 | 60 | #: {{cookiecutter.repo_name}}.py:159 61 | msgid "Exit" 62 | msgstr "Salida" 63 | 64 | #: {{cookiecutter.repo_name}}.py:163 {{cookiecutter.repo_name}}.py:170 65 | msgid "Help" 66 | msgstr "Ayuda" 67 | 68 | #: {{cookiecutter.repo_name}}.py:165 {{cookiecutter.repo_name}}.py:195 69 | msgid "About" 70 | msgstr "Sobre" 71 | 72 | #: {{cookiecutter.repo_name}}.py:169 73 | msgid "File" 74 | msgstr "Archivo" 75 | 76 | #: {{cookiecutter.repo_name}}.py:180 77 | msgid "Help not yet created." 78 | msgstr "Ayudará aún no creado." 79 | 80 | #: {{cookiecutter.repo_name}}.py:188 81 | msgid "No description available" 82 | msgstr "No hay descripción disponible" 83 | 84 | #: {{cookiecutter.repo_name}}.py:190 85 | msgid "Author" 86 | msgstr "Autor" 87 | 88 | #: {{cookiecutter.repo_name}}.py:191 89 | msgid "Email" 90 | msgstr "Email" 91 | 92 | #: {{cookiecutter.repo_name}}.py:192 93 | msgid "Version" 94 | msgstr "Versión" 95 | 96 | #: {{cookiecutter.repo_name}}.py:193 97 | msgid "GitHub Package" 98 | msgstr "GitHub paquete" 99 | 100 | #: {{cookiecutter.repo_name}}.py:201 101 | msgid "New button pressed" 102 | msgstr "Nuevo botón presionado" 103 | 104 | #: {{cookiecutter.repo_name}}.py:201 105 | msgid "Not yet implemented" 106 | msgstr "Aun no implementado" 107 | 108 | #: {{cookiecutter.repo_name}}.py:208 109 | msgid "File selected for open: " 110 | msgstr "Archivo seleccionado para abrir:" 111 | 112 | #: {{cookiecutter.repo_name}}.py:210 113 | msgid "No file selected" 114 | msgstr "Ningún archivo seleccionado" 115 | 116 | #: {{cookiecutter.repo_name}}.py:252 117 | msgid "Uptime" 118 | msgstr "Uptime" 119 | -------------------------------------------------------------------------------- /{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/messages.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR ORGANIZATION 3 | # FIRST AUTHOR , YEAR. 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: PACKAGE VERSION\n" 8 | "POT-Creation-Date: 2016-06-16 11:20+PDT\n" 9 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 10 | "Last-Translator: FULL NAME \n" 11 | "Language-Team: LANGUAGE \n" 12 | "MIME-Version: 1.0\n" 13 | "Content-Type: text/plain; charset=CHARSET\n" 14 | "Content-Transfer-Encoding: ENCODING\n" 15 | "Generated-By: pygettext.py 1.5\n" 16 | 17 | 18 | #: {{cookiecutter.repo_name}}.py:37 19 | msgid "OK" 20 | msgstr "" 21 | 22 | #: {{cookiecutter.repo_name}}.py:61 23 | msgid "Navigation " 24 | msgstr "" 25 | 26 | #: {{cookiecutter.repo_name}}.py:74 27 | msgid "List item" 28 | msgstr "" 29 | 30 | #: {{cookiecutter.repo_name}}.py:88 31 | msgid "Unset status " 32 | msgstr "" 33 | 34 | #: {{cookiecutter.repo_name}}.py:108 35 | msgid "Tool " 36 | msgstr "" 37 | 38 | #: {{cookiecutter.repo_name}}.py:118 39 | msgid "Toolbar button" 40 | msgstr "" 41 | 42 | #: {{cookiecutter.repo_name}}.py:118 43 | msgid "pressed" 44 | msgstr "" 45 | 46 | #: {{cookiecutter.repo_name}}.py:127 47 | msgid "Template" 48 | msgstr "" 49 | 50 | #: {{cookiecutter.repo_name}}.py:155 51 | msgid "New" 52 | msgstr "" 53 | 54 | #: {{cookiecutter.repo_name}}.py:156 55 | msgid "Open" 56 | msgstr "" 57 | 58 | #: {{cookiecutter.repo_name}}.py:159 59 | msgid "Exit" 60 | msgstr "" 61 | 62 | #: {{cookiecutter.repo_name}}.py:163 {{cookiecutter.repo_name}}.py:170 63 | msgid "Help" 64 | msgstr "" 65 | 66 | #: {{cookiecutter.repo_name}}.py:165 {{cookiecutter.repo_name}}.py:195 67 | msgid "About" 68 | msgstr "" 69 | 70 | #: {{cookiecutter.repo_name}}.py:169 71 | msgid "File" 72 | msgstr "" 73 | 74 | #: {{cookiecutter.repo_name}}.py:180 75 | msgid "Help not yet created." 76 | msgstr "" 77 | 78 | #: {{cookiecutter.repo_name}}.py:188 79 | msgid "No description available" 80 | msgstr "" 81 | 82 | #: {{cookiecutter.repo_name}}.py:190 83 | msgid "Author" 84 | msgstr "" 85 | 86 | #: {{cookiecutter.repo_name}}.py:191 87 | msgid "Email" 88 | msgstr "" 89 | 90 | #: {{cookiecutter.repo_name}}.py:192 91 | msgid "Version" 92 | msgstr "" 93 | 94 | #: {{cookiecutter.repo_name}}.py:193 95 | msgid "GitHub Package" 96 | msgstr "" 97 | 98 | #: {{cookiecutter.repo_name}}.py:201 99 | msgid "New button pressed" 100 | msgstr "" 101 | 102 | #: {{cookiecutter.repo_name}}.py:201 103 | msgid "Not yet implemented" 104 | msgstr "" 105 | 106 | #: {{cookiecutter.repo_name}}.py:208 107 | msgid "File selected for open: " 108 | msgstr "" 109 | 110 | #: {{cookiecutter.repo_name}}.py:210 111 | msgid "No file selected" 112 | msgstr "" 113 | 114 | #: {{cookiecutter.repo_name}}.py:252 115 | msgid "Uptime" 116 | msgstr "" 117 | 118 | -------------------------------------------------------------------------------- /{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}/{{cookiecutter.repo_name}}.py: -------------------------------------------------------------------------------- 1 | """ 2 | {{cookiecutter.repo_name}} 3 | ----------------- 4 | 5 | {{cookiecutter.short_description}} 6 | """ 7 | 8 | import datetime 9 | import gettext 10 | import sys 11 | import time 12 | import tkinter 13 | import tkinter.ttk as ttk 14 | from tkinter.filedialog import askopenfilename 15 | 16 | # All translations provided for illustrative purposes only. 17 | {% if cookiecutter.language == 'german' %} 18 | de = gettext.translation('messages', localedir='locale', languages=['de']) 19 | de.install() 20 | {% elif cookiecutter.language == 'spanish' %} 21 | es = gettext.translation('messages', localedir='locale', languages=['es']) 22 | es.install() 23 | {% else %} # english 24 | _ = lambda s: s 25 | {% endif %} 26 | 27 | 28 | class PopupDialog(ttk.Frame): 29 | "Sample popup dialog implemented to provide feedback." 30 | 31 | def __init__(self, parent, title, body): 32 | ttk.Frame.__init__(self, parent) 33 | self.top = tkinter.Toplevel(parent) 34 | _label = ttk.Label(self.top, text=body, justify=tkinter.LEFT) 35 | _label.pack(padx=10, pady=10) 36 | _button = ttk.Button(self.top, text=_("OK"), command=self.ok_button) 37 | _button.pack(pady=5) 38 | self.top.title(title) 39 | 40 | def ok_button(self): 41 | "OK button feedback." 42 | 43 | self.top.destroy() 44 | 45 | 46 | {% if cookiecutter.insert_navigation == 'y' %} 47 | class NavigationBar(ttk.Frame): 48 | "Sample navigation pane provided by cookiecutter switch." 49 | 50 | def __init__(self, parent): 51 | ttk.Frame.__init__(self, parent) 52 | self.config(border=1, relief=tkinter.GROOVE) 53 | 54 | self.scrollbar = ttk.Scrollbar(self, orient=tkinter.VERTICAL) 55 | self.scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y, expand=1) 56 | 57 | self.listbox = tkinter.Listbox(self, bg='white') 58 | self.listbox.pack(side=tkinter.LEFT, fill=tkinter.BOTH, expand=1) 59 | for i in range(1, 100): 60 | self.listbox.insert(tkinter.END, _('Navigation ') + str(i)) 61 | self.listbox.config(yscrollcommand=self.scrollbar.set) 62 | self.scrollbar.config(command=self.listbox.yview) 63 | self.bind_all('<>', self.onselect) 64 | self.pack() 65 | 66 | def onselect(self, event): 67 | """Sample function provided to show how navigation commands may be \ 68 | received.""" 69 | 70 | widget = event.widget 71 | _index = int(widget.curselection()[0]) 72 | _value = widget.get(_index) 73 | print(_('List item'), ' %d / %s' % (_index, _value)) 74 | {% endif %} 75 | 76 | 77 | {% if cookiecutter.insert_status == 'y' %} 78 | class StatusBar(ttk.Frame): 79 | "Sample status bar provided by cookiecutter switch." 80 | _status_bars = 4 81 | 82 | def __init__(self, parent): 83 | ttk.Frame.__init__(self, parent) 84 | self.labels = [] 85 | self.config(border=1, relief=tkinter.GROOVE) 86 | for i in range(self._status_bars): 87 | _label_text = _('Unset status ') + str(i + 1) 88 | self.labels.append(ttk.Label(self, text=_label_text)) 89 | self.labels[i].config(relief=tkinter.GROOVE) 90 | self.labels[i].pack(side=tkinter.LEFT, fill=tkinter.X) 91 | self.pack() 92 | 93 | def set_text(self, status_index, new_text): 94 | self.labels[status_index].config(text=new_text) 95 | {% endif %} 96 | 97 | 98 | {% if cookiecutter.insert_toolbar == 'y' %} 99 | class ToolBar(ttk.Frame): 100 | "Sample toolbar provided by cookiecutter switch." 101 | 102 | def __init__(self, parent): 103 | ttk.Frame.__init__(self, parent) 104 | self.buttons = [] 105 | self.config(border=1, relief=tkinter.GROOVE) 106 | for i in range(1, 5): 107 | _button_text = _('Tool ') + str(i) 108 | self.buttons.append(ttk.Button(self, text=_button_text, 109 | command=lambda i=i: 110 | self.run_tool(i))) 111 | self.buttons[i - 1].pack(side=tkinter.LEFT, fill=tkinter.X) 112 | self.pack() 113 | 114 | def run_tool(self, number): 115 | "Sample function provided to show how a toolbar command may be used." 116 | 117 | print(_('Toolbar button'), number, _('pressed')) 118 | {% endif %} 119 | 120 | 121 | class MainFrame(ttk.Frame): 122 | "Main area of user interface content." 123 | 124 | past_time = datetime.datetime.now() 125 | _advertisement = 'Cookiecutter: Open-Source Project Templates' 126 | _product = _('Template') + ': {{cookiecutter.display_name}}' 127 | _boilerplate = _advertisement + '\n\n' + _product + '\n\n' 128 | 129 | def __init__(self, parent): 130 | ttk.Frame.__init__(self, parent) 131 | self.display = ttk.Label(parent, anchor=tkinter.CENTER, 132 | foreground='green', background='black') 133 | self.display.pack(fill=tkinter.BOTH, expand=1) 134 | self.tick() 135 | 136 | def tick(self): 137 | "Invoked automatically to update a clock displayed in the GUI." 138 | 139 | this_time = datetime.datetime.now() 140 | if this_time != self.past_time: 141 | self.past_time = this_time 142 | _timestamp = this_time.strftime('%Y-%m-%d %H:%M:%S') 143 | self.display.config(text=self._boilerplate + _timestamp) 144 | self.display.after(100, self.tick) 145 | 146 | 147 | class MenuBar(tkinter.Menu): 148 | "Menu bar appearing with expected components." 149 | 150 | def __init__(self, parent): 151 | tkinter.Menu.__init__(self, parent) 152 | 153 | filemenu = tkinter.Menu(self, tearoff=False) 154 | filemenu.add_command(label=_('New'), command=self.new_dialog) 155 | filemenu.add_command(label=_('Open'), command=self.open_dialog) 156 | filemenu.add_separator() 157 | filemenu.add_command(label=_('Exit'), underline=1, 158 | command=self.quit) 159 | 160 | helpmenu = tkinter.Menu(self, tearoff=False) 161 | helpmenu.add_command(label=_('Help'), command=lambda: 162 | self.help_dialog(None), accelerator="F1") 163 | helpmenu.add_command(label=_('About'), command=self.about_dialog) 164 | self.bind_all('', self.help_dialog) 165 | 166 | self.add_cascade(label=_('File'), underline=0, menu=filemenu) 167 | self.add_cascade(label=_('Help'), underline=0, menu=helpmenu) 168 | 169 | def quit(self): 170 | "Ends toplevel execution." 171 | 172 | sys.exit(0) 173 | 174 | def help_dialog(self, event): 175 | "Dialog cataloging results achievable, and provided means available." 176 | 177 | _description = _('Help not yet created.') 178 | PopupDialog(self, '{{cookiecutter.display_name}}', _description) 179 | 180 | def about_dialog(self): 181 | "Dialog concerning information about entities responsible for program." 182 | 183 | _description = '{{cookiecutter.short_description}}' 184 | if _description == '': 185 | _description = _('No description available') 186 | _description += '\n' 187 | _description += '\n' + _('Author') + ': {{cookiecutter.full_name}}' 188 | _description += '\n' + _('Email') + ': {{cookiecutter.email}}' 189 | _description += '\n' + _('Version') + ': {{cookiecutter.version}}' 190 | _description += '\n' + _('GitHub Package') + \ 191 | ': {{cookiecutter.repo_name}}' 192 | PopupDialog(self, _('About') + ' {{cookiecutter.display_name}}', 193 | _description) 194 | 195 | def new_dialog(self): 196 | "Non-functional dialog indicating successful navigation." 197 | 198 | PopupDialog(self, _('New button pressed'), _('Not yet implemented')) 199 | 200 | def open_dialog(self): 201 | "Standard askopenfilename() invocation and result handling." 202 | 203 | _name = tkinter.filedialog.askopenfilename() 204 | if isinstance(_name, str): 205 | print(_('File selected for open: ') + _name) 206 | else: 207 | print(_('No file selected')) 208 | 209 | 210 | class Application(tkinter.Tk): 211 | "Create top-level Tkinter widget containing all other widgets." 212 | 213 | def __init__(self): 214 | tkinter.Tk.__init__(self) 215 | menubar = MenuBar(self) 216 | self.config(menu=menubar) 217 | self.wm_title('{{cookiecutter.display_name}}') 218 | self.wm_geometry('640x480') 219 | 220 | {% if cookiecutter.insert_status == 'y' %}# Status bar selection == 'y' 221 | self.statusbar = StatusBar(self) 222 | self.statusbar.pack(side='bottom', fill='x') 223 | self.bind_all('', lambda e: self.statusbar.set_text(0, 224 | 'Mouse: 1')) 225 | self.bind_all('', lambda e: self.statusbar.set_text(0, 226 | 'Mouse: 0')) 227 | self.bind_all('', lambda e: self.statusbar.set_text(1, 228 | 'Clicked at x = ' + str(e.x) + ' y = ' + str(e.y))) 229 | self.start_time = datetime.datetime.now() 230 | self.uptime() 231 | {% endif %} 232 | 233 | {% if cookiecutter.insert_navigation == 'y' %}# Navigation selection == 'y' 234 | self.navigationbar = NavigationBar(self) 235 | self.navigationbar.pack(side='left', fill='y') 236 | {% endif %} 237 | 238 | {% if cookiecutter.insert_toolbar == 'y' %}# Tool bar selection == 'y' 239 | self.toolbar = ToolBar(self) 240 | self.toolbar.pack(side='top', fill='x') 241 | {% endif %} 242 | 243 | self.mainframe = MainFrame(self) 244 | self.mainframe.pack(side='right', fill='y') 245 | 246 | {% if cookiecutter.insert_status == 'y' %}# Status bar selection == 'y' 247 | def uptime(self): 248 | _upseconds = str(int(round((datetime.datetime.now() - self.start_time).total_seconds()))) 249 | self.statusbar.set_text(2, _('Uptime') + ': ' + _upseconds) 250 | self.after(1000, self.uptime) 251 | {% endif %} 252 | 253 | if __name__ == '__main__': 254 | APPLICATION_GUI = Application() 255 | APPLICATION_GUI.mainloop() 256 | --------------------------------------------------------------------------------