grid_gui.py


directory : D:\2018_py_proj\TkGridGUI\tkgridgui
Line Count : 1003
Line Clip Size : No Clipping

tab_of_notebook_changed  Word MatchCase (5) 161 495 498 788 910 
1 #!/usr/bin/env python 2 # -*- coding: ascii -*- 3 from __future__ import print_function 4 from __future__ import unicode_literals 5 from future import standard_library 6 standard_library.install_aliases() 7 from builtins import str 8 from builtins import range 9 from builtins import object 10 r""" 11 tkGridGUI builds a target python Tkinter GUI graphic user interface using 12 the grid geometry manager. 13 14 The main idea behind tkGridGUI is to allow a fully "wired" python 15 Tkinter GUI application to be created in minutes. The users main 16 responsibility is to add logic to the Tkinter framework created by tkGridGUI. 17 tkGridGUI holds structures to create items such as menus, toolbars and statusbars. 18 19 TkGridGUI 20 Copyright (C) 2018 Charlie Taylor 21 22 This program is free software: you can redistribute it and/or modify 23 it under the terms of the GNU General Public License as published by 24 the Free Software Foundation, either version 3 of the License, or 25 (at your option) any later version. 26 27 This program is distributed in the hope that it will be useful, 28 but WITHOUT ANY WARRANTY; without even the implied warranty of 29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 GNU General Public License for more details. 31 32 You should have received a copy of the GNU General Public License 33 along with this program. If not, see <http://www.gnu.org/licenses/>. 34 35 ----------------------- 36 37 """ 38 import os 39 here = os.path.abspath(os.path.dirname(__file__)) 40 41 __author__ = 'Charlie Taylor' 42 __copyright__ = 'Copyright (c) 2018 Charlie Taylor' 43 __license__ = 'GPL-3' 44 exec( open(os.path.join( here,'_version.py' )).read() ) # creates local __version__ variable 45 __email__ = "cet@appliedpython.com" 46 __status__ = "3 - Alpha" # "3 - Alpha", "4 - Beta", "5 - Production/Stable" 47 48 49 import sys 50 from sys import platform 51 52 if sys.version_info < (3,): 53 from tkSimpleDialog import Dialog 54 else: 55 from tkinter.simpledialog import Dialog 56 57 from tkinter import * 58 import tkinter.messagebox 59 import tkinter.filedialog 60 import tkinter.colorchooser 61 from tkinter import Button, Canvas, Checkbutton, Entry, Frame, Label, LabelFrame 62 from tkinter import Listbox, Message, Radiobutton, Spinbox, Text 63 from tkinter import OptionMenu # ttk OptionMenu seems to be broken 64 from tkinter.ttk import Combobox, Progressbar, Separator, Treeview, Style, Notebook 65 66 from tkgridgui.tkfontchooser import askfont 67 68 from tkgridgui.grid_notebook import NotebookGridDes, CONTROLS, ContainerControlsL, CONTROL_NEXT_NUMBER_D, CONTROL_COLOR_D 69 from tkgridgui.target_tk_app_def import TargetTkAppDef # used to read and save App Definition 70 from tkgridgui.preview_win import PreviewWin 71 72 from tkgridgui.menu_maker_Dialog import Menumaker 73 from tkgridgui.make_py_src import FormSource 74 from tkgridgui.make_menu_src import buildMenuSource, getMenuSource 75 76 from tkgridgui.maybe_save_Dialog import maybe_save_dialog 77 78 class GridGUI(object): 79 """ 80 tkGridGUI builds a python Tkinter GUI graphic user interface using the grid geometry manager. 81 """ 82 83 def __init__(self, MainWin): 84 """Inits Tkinter window of GridGUI.""" 85 86 self.root = MainWin 87 #MainWin.geometry("800x600") #You want the size of the app to be 500x500 88 MainWin.geometry( '+10+30' ) 89 90 try: 91 style = Style(self.root) 92 if "win" == platform[:3]: 93 style.theme_use('vista') 94 elif "darwin" in platform: 95 style.theme_use('clam') 96 else: 97 style.theme_use('clam') 98 bg = style.lookup("TLabel", "background") 99 self.root.configure(bg=bg) 100 except: 101 print("OOPS... failed to set style.theme_use... Let's press on.") 102 103 self.MainWin = MainWin 104 105 MainWin.protocol('WM_DELETE_WINDOW', self.cleanupOnQuit) 106 MainWin.allow_subWindows_to_close = 0 107 108 self.add_menu_to_MainWin() 109 110 topFrame = Frame( MainWin ) # frame for controls 111 #topFrame = tx.ScrolledWindow( MainWin ) 112 113 frame1 = LabelFrame(topFrame, text="Widgets") 114 self.place_widget_selection_listbox( frame1 ) 115 frame1.pack(anchor=NW, side=LEFT) 116 117 frame2 = Frame( topFrame ) # frame for radio buttons 118 self.place_gui_definition_controls( frame2, MainWin ) 119 frame2.pack(anchor=N, side=LEFT) 120 121 self.grid_frame = Frame(topFrame) 122 self.grid_notebook = NotebookGridDes(self, self.grid_frame, MainWin, num_cols=5, num_rows=8) 123 self.grid_frame.pack(anchor=N, side=LEFT) 124 125 topFrame.pack(fill=BOTH, expand=Y) 126 127 # make a Status Bar 128 statframe = Frame(MainWin) 129 MainWin.statusMessage = StringVar() 130 MainWin.statusMessage.set('Welcome to TkGridGUI') 131 self.statusbar = Label(statframe, textvariable=MainWin.statusMessage, 132 relief=SUNKEN, anchor=W) 133 self.statusbar.pack(anchor=SW, fill=X, side=BOTTOM) 134 statframe.pack(anchor=SW, fill=X, side=BOTTOM) 135 136 # Initialize some GridGUI parameters 137 138 self.current_fileFullName = '' # no file for now 139 self.current_filePath = '' # no file for now 140 self.current_fileName = '' # no file for now 141 142 self.target_app = TargetTkAppDef( name='myApp') 143 self.PreviewWin = None # need to initialize later 144 145 self.Listbox_1_Click( None ) # execute selection logic 146 147 148 self.in_reading_mode = False # when True, suppresses some automatic trace actions. 149 if len( sys.argv ) == 2: 150 fName = sys.argv[1] 151 if fName.find('.')<0: 152 fName += '.def' 153 154 fullpath = os.path.abspath(fName) 155 156 if os.path.isfile( fullpath ): # if file exists, read it as a definition file 157 self.openFile( fName=fullpath ) 158 else: 159 self.MainWin.statusMessage.set('file "%s" does not exist'%fName) 160 161 self.grid_notebook.notebook.bind("<<NotebookTabChanged>>", self.tab_of_notebook_changed) 162 163 self.mouse_location = '' 164 self.MainWin.bind("<Enter>", self.onMainWindowEnter) 165 166 def onMainWindowEnter(self, event): 167 """Only track Enter... Want last known location.""" 168 if self.mouse_location != 'main_window': 169 print('mouse_location = main_window') 170 self.mouse_location = 'main_window' 171 172 def refresh_preview_win(self, allow_destroy_children=True): 173 """ 174 Place all of the widgets from grid_notebook onto PreviewWin. 175 May need to delete and rebuild current widgets on PreviewWin. 176 """ 177 178 if self.PreviewWin is None: 179 self.PreviewWin = PreviewWin( self.MainWin, grid_gui=self ) 180 self.target_app.set_PreviewWin( self.PreviewWin ) 181 self.target_app.set_Notebook( self.grid_notebook ) 182 else: 183 if allow_destroy_children: 184 self.PreviewWin.destroy_all_children() 185 self.target_app.destroy_all_preview_widgets() 186 187 188 widgetL = self.grid_notebook.make_complete_list_of_widgets() 189 #print("========== PreviewWin Widget Info.") 190 for w in widgetL: 191 #print( w ) 192 (widget_type, widget_name, tab_label, row_target, col_target) = w 193 194 self.target_app.maybe_add_component( widget_type=widget_type, 195 widget_name=widget_name, 196 tab_label=tab_label, 197 row=row_target, col=col_target) 198 self.target_app.show_preview() 199 #print("="*55) 200 #print('ref crc_reference =',self.target_app.crc_reference, 'current =', self.target_app.get_model_crc() ) 201 202 203 204 def add_menu_to_MainWin(self): 205 206 # make menus 207 self.menuBar = Menu(self.MainWin, relief = 'raised', bd=2) 208 209 # create file pulldown menu 210 fileMenu = Menu(self.menuBar, tearoff=0) 211 fileMenu.add('command', label = 'New', command=self.newForm, underline=0,accelerator="Ctrl+N") 212 fileMenu.add('command', label = 'Open', command=self.openFile, underline=0,accelerator="Ctrl+O") 213 fileMenu.add('command', label = 'Save', command=self.saveasFile, underline=0,accelerator="Ctrl+S") 214 #fileMenu.add('command', label = 'SaveAs', command = self.saveasFile) 215 fileMenu.add('command', label = 'Exit', command=self.cleanupOnQuit, underline=0,accelerator="Ctrl+X") 216 self.menuBar.add('cascade', label="File", menu=fileMenu) 217 218 # create options pulldown menu 219 optMenu = Menu(self.menuBar, tearoff=0) 220 optMenu.add('command', label = 'Font to Clipboard', command =self.FontPickButton_Select, underline=0,accelerator="Ctrl+F") 221 optMenu.add('command', label = 'Color to Clipboard', command = self.ColorPickButton_Select, underline=0,accelerator="Ctrl+C") 222 self.menuBar.add('cascade', label="Options", menu=optMenu) 223 224 # bind accelerator keys (need lambda since functions don't have "event" parameter) 225 self.root.bind("<Control-N>", lambda event: self.newForm()) 226 self.root.bind("<Control-n>", lambda event: self.newForm()) 227 228 self.root.bind("<Control-O>", lambda event: self.openFile()) 229 self.root.bind("<Control-o>", lambda event: self.openFile()) 230 231 self.root.bind("<Control-S>", lambda event: self.saveasFile()) 232 self.root.bind("<Control-s>", lambda event: self.saveasFile()) 233 234 self.root.bind("<Control-X>", lambda event: self.cleanupOnQuit()) 235 self.root.bind("<Control-x>", lambda event: self.cleanupOnQuit()) 236 237 # create About menu 238 self.menuBar.add('command', label="About", command = self.About) 239 240 # create Help menu 241 self.menuBar.add('command', label="Help", command = self.Help) 242 243 self.root.config(menu=self.menuBar) 244 245 def mainOrDialog_Callback(self, varName, index, mode): 246 #print( "mainOrDialog_Callback varName, index, mode",varName, index, mode ) 247 #print( " new StringVar value =",self.MainWin.mainOrDialog.get() ) 248 249 self.refresh_preview_win() 250 if self.MainWin.mainOrDialog.get() == 'dialog': 251 if self.MainWin.hideOkChkBox_StringVar.get() == "yes": 252 self.PreviewWin.remove_mock_OK_Cancel_Buttons() 253 else: 254 self.PreviewWin.add_mock_OK_Cancel_Buttons() 255 else: 256 self.PreviewWin.remove_mock_OK_Cancel_Buttons() 257 258 def place_gui_definition_controls(self, frame2, MainWin ): 259 260 # show option for Main Window or Dialog 261 MainWin.mainOrDialog=StringVar() 262 lbframe = LabelFrame(frame2, text="GUI Type") 263 lbframe.pack(anchor=W) 264 265 b = Radiobutton(lbframe, text="Main Window", value='main', variable=MainWin.mainOrDialog) 266 b.pack(anchor=W) 267 b = Radiobutton(lbframe, text="Dialog", value='dialog', variable=MainWin.mainOrDialog) 268 b.pack(anchor=W) 269 MainWin.mainOrDialog.set('main') 270 self.mainOrDialog_traceName = MainWin.mainOrDialog.trace_variable("w", self.mainOrDialog_Callback) 271 272 MainWin.hideOkChkBox = Checkbutton(lbframe, text="Hide OK Btn", width="15") 273 MainWin.hideOkChkBox.pack(anchor=E, side=TOP) 274 MainWin.hideOkChkBox_StringVar = StringVar() 275 MainWin.hideOkChkBox_StringVar.set("no") 276 MainWin.hideOkChkBox.configure(variable=MainWin.hideOkChkBox_StringVar, onvalue="yes", offvalue="no") 277 self.hideOkChkBox_traceName = MainWin.hideOkChkBox_StringVar.trace_variable("w", self.hideOkChkBox_Callback) 278 279 # show checkbox for menu and status bar 280 lbframe = LabelFrame(frame2, text="Window Options") 281 lbframe.pack(anchor=W) 282 283 MainWin.menuChkBox = Checkbutton(lbframe, text="Main Menu", width="15") 284 MainWin.menuChkBox.pack(anchor=W, side=TOP) 285 MainWin.menuChkBox_StringVar = StringVar() 286 MainWin.menuChkBox_StringVar.set("no") 287 MainWin.menuChkBox.configure(variable=MainWin.menuChkBox_StringVar, onvalue="yes", offvalue="no") 288 self.menuChkBox_traceName = MainWin.menuChkBox_StringVar.trace_variable("w", self.menuChkBox_Callback) 289 290 MainWin.statusBarChkBox = Checkbutton(lbframe, text="Status Bar", width="15") 291 MainWin.statusBarChkBox.pack(anchor=W, side=TOP) 292 MainWin.statusBarChkBox_StringVar = StringVar() 293 MainWin.statusBarChkBox_StringVar.set("no") 294 MainWin.statusBarChkBox.configure(variable=MainWin.statusBarChkBox_StringVar, onvalue="yes", offvalue="no") 295 self.statusBarChkBox_traceName = MainWin.statusBarChkBox_StringVar.trace_variable("w", self.statusBarChkBox_Callback) 296 297 MainWin.resizableChkBox = Checkbutton(lbframe, text="Resizable", width="15") 298 MainWin.resizableChkBox.pack(anchor=W, side=TOP) 299 MainWin.resizableChkBox_StringVar = StringVar() 300 MainWin.resizableChkBox_StringVar.set("yes") 301 MainWin.resizableChkBox.configure(variable=MainWin.resizableChkBox_StringVar, onvalue="yes", offvalue="no") 302 self.resizableChkBox_traceName = MainWin.resizableChkBox_StringVar.trace_variable("w", self.resizableChkBox_Callback) 303 304 # show choices for standard dialogs 305 lbframe = LabelFrame(frame2, text="Standard Dialogs") 306 lbframe.pack(anchor=W) 307 308 MainWin.stdDialMessChkBox = Checkbutton(lbframe, text="Messages", width="15") 309 MainWin.stdDialMessChkBox.pack(anchor=E, side=TOP) 310 MainWin.stdDialMessChkBox_StringVar = StringVar() 311 MainWin.stdDialMessChkBox_StringVar.set("no") 312 MainWin.stdDialMessChkBox.configure(variable=MainWin.stdDialMessChkBox_StringVar, onvalue="yes", offvalue="no") 313 314 315 MainWin.stdDialColorChkBox = Checkbutton(lbframe, text="Color Choose", width="15") 316 MainWin.stdDialColorChkBox.pack(anchor=E, side=TOP) 317 MainWin.stdDialColorChkBox_StringVar = StringVar() 318 MainWin.stdDialColorChkBox_StringVar.set("no") 319 MainWin.stdDialColorChkBox.configure(variable=MainWin.stdDialColorChkBox_StringVar, onvalue="yes", offvalue="no") 320 321 MainWin.stdDialFileChkBox = Checkbutton(lbframe, text="File Open/Save", width="15") 322 MainWin.stdDialFileChkBox.pack(anchor=E, side=TOP) 323 MainWin.stdDialFileChkBox_StringVar = StringVar() 324 MainWin.stdDialFileChkBox_StringVar.set("no") 325 MainWin.stdDialFileChkBox.configure(variable=MainWin.stdDialFileChkBox_StringVar, onvalue="yes", offvalue="no") 326 327 MainWin.stdAlarmChkBox = Checkbutton(lbframe, text="Alarm Handler", width="15") 328 MainWin.stdAlarmChkBox.pack(anchor=E, side=TOP) 329 MainWin.stdAlarmChkBox_StringVar = StringVar() 330 MainWin.stdAlarmChkBox_StringVar.set("no") 331 MainWin.stdAlarmChkBox.configure(variable=MainWin.stdAlarmChkBox_StringVar, onvalue="yes", offvalue="no") 332 333 # put color picker button 334 self.ColorPickButton = Button(frame2, text="Put Color on Clipboard", width=18) 335 self.ColorPickButton.pack(anchor=W, side=TOP) 336 self.ColorPickButton.bind("<ButtonRelease-1>", self.ColorPickButton_Click) 337 338 # put Font picker button 339 self.FontPickButton = Button(frame2, text="Put Font on Clipboard", width=18) 340 self.FontPickButton.pack(anchor=W, side=TOP) 341 self.FontPickButton.bind("<ButtonRelease-1>", self.FontPickButton_Click) 342 343 # put All widgets on notebook 344 #self.PlaceAllWidgetsButton = Button(frame2, text="Debug All Widgets", width=18) 345 #self.PlaceAllWidgetsButton.pack(anchor=W, side=TOP) 346 #self.PlaceAllWidgetsButton.bind("<ButtonRelease-1>", self.PlaceAllWidgetsButton_Click) 347 348 # append new row or column to current notebook tab 349 add_frame = Frame( frame2 ) 350 self.AddNewRowButton = Button(add_frame, text="Add Row", width=8) 351 self.AddNewRowButton.pack(anchor=W, side=LEFT) 352 self.AddNewRowButton.bind("<ButtonRelease-1>", self.AddNewRowButton_Click) 353 354 self.AddNewColButton = Button(add_frame, text="Add Col", width=8) 355 self.AddNewColButton.pack(anchor=W, side=LEFT) 356 self.AddNewColButton.bind("<ButtonRelease-1>", self.AddNewColButton_Click) 357 add_frame.pack(anchor=W, side=TOP) 358 359 # dup_widget_label can be used for set_placement_widget_label, or widget duplication 360 self.dup_widget_label_desc = Label(frame2, width=16) 361 self.dup_widget_label_desc["text" ] = "\nduplicate widget\nand its properties" 362 self.dup_widget_label_desc.pack(anchor=W) 363 364 self.dup_widget_label = Label(frame2, width=16) 365 self.dup_widget_label["text" ] = "\n\n" 366 self.dup_widget_label["font" ] = ("Courier", 8, "normal") 367 self.dup_widget_label["relief"] = "groove" 368 self.dup_widget_label.pack(anchor=W) 369 self.dup_widget_label_plain_bg = self.dup_widget_label["background"] 370 self.dup_widget_label["background"] = "#FFFACD" # lemonchiffon 371 372 # Refresh Preview Window 373 #self.PlaceAllWidgetsButton = Button(frame2, text="Refresh Preview", width=18) 374 #self.PlaceAllWidgetsButton.pack(anchor=W, side=TOP) 375 #self.PlaceAllWidgetsButton.bind("<ButtonRelease-1>", self.GeneralDebugButton_Click) 376 377 def GeneralDebugButton_Click(self, event): 378 self.grid_notebook.repaint_all_labels() 379 self.refresh_preview_win() 380 381 def AddNewRowButton_Click(self, event): 382 self.grid_notebook.append_row() 383 384 def AddNewColButton_Click(self, event): 385 self.grid_notebook.append_column() 386 387 388 def PlaceAllWidgetsButton_Click(self, event): 389 """As debug tool, show all widgets in Notebook""" 390 391 saved_sel = self.MainWin.placementWidgetType_svar.get() 392 saved_tab = self.grid_notebook.current_tab_label() 393 394 row = 1 # row_interface 395 col = 1 # col_interface 396 397 self.grid_notebook.set_current_tab_by_label( "Main" ) 398 399 for wname, wcolor in CONTROLS: 400 self.MainWin.placementWidgetType_svar.set( wname ) 401 event.widget = self.grid_notebook.interface_gridBoxWidgetD[("Main", row, col)]# row_interface, col_interface 402 self.grid_notebook.onGridBoxClicked( event ) 403 404 if wname in ContainerControlsL: 405 new_tab_name = wname + "_%i"%(CONTROL_NEXT_NUMBER_D[wname] -1,) 406 self.grid_notebook.set_current_tab_by_label( new_tab_name ) 407 408 # place some widgets on ContainerControlsL tab 409 if wname == 'RadioGroup': 410 self.MainWin.placementWidgetType_svar.set( "Label" ) 411 event.widget = self.grid_notebook.interface_gridBoxWidgetD[(new_tab_name, 2, 2)]# row_interface, col_interface 412 self.grid_notebook.onGridBoxClicked( event ) 413 414 for n_radio in range(3): 415 self.MainWin.placementWidgetType_svar.set( "Radiobutton" ) 416 event.widget = self.grid_notebook.interface_gridBoxWidgetD[(new_tab_name, 3+n_radio, 2)]# row_interface, col_interface 417 self.grid_notebook.onGridBoxClicked( event ) 418 419 420 else: 421 self.MainWin.placementWidgetType_svar.set( "Button" ) 422 event.widget = self.grid_notebook.interface_gridBoxWidgetD[(new_tab_name, 2, 2)]# row_interface, col_interface 423 self.grid_notebook.onGridBoxClicked( event ) 424 425 self.MainWin.placementWidgetType_svar.set( "Label" ) 426 event.widget = self.grid_notebook.interface_gridBoxWidgetD[(new_tab_name, 3, 2)]# row_interface, col_interface 427 self.grid_notebook.onGridBoxClicked( event ) 428 429 self.MainWin.placementWidgetType_svar.set( "Entry" ) 430 event.widget = self.grid_notebook.interface_gridBoxWidgetD[(new_tab_name, 4, 2)]# row_interface, col_interface 431 self.grid_notebook.onGridBoxClicked( event ) 432 433 # restore notebook to Main tab 434 self.grid_notebook.set_current_tab_by_label( "Main" ) 435 436 437 col += 1 438 if col % 5 == 0: 439 col = 1 440 row += 1 441 442 # Return Listbox_1 selection to original value 443 self.MainWin.placementWidgetType_svar.set( saved_sel ) 444 self.grid_notebook.set_current_tab_by_label( saved_tab ) 445 446 def set_status_msg(self, msg): 447 self.MainWin.statusMessage.set( msg ) 448 449 def gray_out_listbox(self, omit_list=None): 450 """if omit_list is None, gray all.""" 451 if omit_list is None: 452 omit_list = [] 453 454 n = -1 455 for index, (wname, wcolor) in enumerate(CONTROLS): 456 if wname in omit_list: 457 self.Listbox_1.itemconfig(index, fg="black") 458 n = index 459 else: 460 self.Listbox_1.itemconfig(index, fg="gray") 461 self.Listbox_1.selection_clear(index) 462 463 if n >= 0: 464 self.Listbox_1.selection_set(n) 465 self.Listbox_1_Click( None ) # event is not used in Listbox_1_Click 466 467 def restore_black_listbox(self): 468 """Make sure all listbox options show up for all other tabs.""" 469 470 n = 0 471 for i in self.Listbox_1.curselection(): 472 n = i 473 break # set to 1st value encountered 474 475 for index, (wname, wcolor) in enumerate(CONTROLS): 476 self.Listbox_1.itemconfig(index, fg="black") 477 self.Listbox_1.selection_clear(index) 478 479 self.Listbox_1.selection_set(n) 480 self.Listbox_1_Click( None ) # event is not used in Listbox_1_Click 481 482 def select_preview_tab(self, tab_name_inp): 483 484 if not self.PreviewWin: 485 self.refresh_preview_win() # make PreviewWin if not already done. 486 487 tab_comp = self.target_app.compObjD[tab_name_inp] 488 notebook_name = tab_comp.tab_label 489 nb_obj = self.target_app.compObjD[ notebook_name ] 490 491 # get index of tab on preview_win 492 for itab, (row, col, tab_name, tab_label) in enumerate( nb_obj.tab_nameL ): 493 if tab_name_inp == tab_name: 494 nb_obj.pw_widget.native_widget.select( itab ) 495 #print('grid_gui.tab_of_notebook_changed: set PreviewWin Tab to:', itab) 496 break 497 498 def tab_of_notebook_changed(self, event): 499 nb = self.grid_notebook.notebook 500 #i = nb.index(nb.select()) 501 text = nb.tab(nb.select(), "text") 502 #print("GridGUI Notebook Tab Set to:", text ) 503 504 self.Listbox_1.config( state=NORMAL ) 505 506 # gray out some listbox options for RadioGroup 507 if text.startswith('RadioGroup'): 508 self.gray_out_listbox( omit_list=("Radiobutton","Label") ) 509 510 elif text.startswith('Notebook'): 511 #print('=========> Need to add Notebook logic.') 512 513 self.gray_out_listbox( omit_list=None ) 514 self.set_placement_widget_label( 'Tab' ) 515 self.set_status_msg( "Only Tabs can be added to Notebook" ) 516 517 else: 518 # Make sure all listbox options show up for all other tabs. 519 self.restore_black_listbox() 520 521 # Cause PreviewWin to switch to same Tab 522 if text.startswith('Tab_'): 523 self.select_preview_tab( text ) # text is tab_name 524 525 526 def place_widget_selection_listbox(self, frame1): 527 """frame1 in topFrame contains Widgets selection ListBox""" 528 529 self.MainWin.placementWidgetType_svar=StringVar() 530 self.MainWin.placementWidgetType_svar.set('Button') 531 532 # Notebooks handled seperately 533 534 self.Listbox_1 = Listbox(frame1,width=15 ,height=str(len(CONTROLS)), selectmode='single')#, selectmode="extended") 535 self.Listbox_1.bind("<ButtonRelease-1>", self.Listbox_1_Click) 536 537 for wname, wcolor in CONTROLS: 538 #b = Radiobutton(frame1, text=text, value=cont, variable=self.MainWin.placementWidgetType_svar) 539 #b.pack(anchor=W) 540 #print("inserting wname into Listbox_1 "+wname) 541 self.Listbox_1.insert(END, wname) 542 543 self.Listbox_1.pack(anchor=W) 544 self.Listbox_1.select_set(0) # make Top Item highlighted 545 546 def cleanupOnQuit(self): 547 548 if self.target_app.model_has_changed(): 549 dialog = maybe_save_dialog(self.MainWin, "Save Before Exit?") 550 551 if (dialog.result is not None) and ( dialog.result['save_file'] == "yes"): 552 self.saveasFile() 553 return 554 else: 555 # ignore any other warnings 556 self.target_app.reset_crc_reference() # for detecting changes to model 557 558 559 #print( 'Doing final cleanup before quitting' ) 560 self.MainWin.allow_subWindows_to_close = 1 561 self.MainWin.destroy() 562 563 def set_duplication_widget_label(self, label_obj): 564 """Given the widget Label object, set up for making duplicates.""" 565 566 self.dup_widget_label["text" ] = label_obj["text"] 567 self.dup_widget_label["background"] = label_obj["background"] 568 self.dup_widget_label_desc["text" ] = "\nduplicate widget\nand its properties" 569 570 def set_placement_widget_label(self, widget_type): 571 """Sets dup_widget_label for a simple Place of widget_type.""" 572 573 self.dup_widget_label["text" ] = "\n%s\n"%widget_type 574 #self.dup_widget_label["background"] = self.dup_widget_label_plain_bg # "#FFFACD" # lemonchiffon 575 self.dup_widget_label["background"] = CONTROL_COLOR_D[widget_type] 576 self.dup_widget_label_desc["text" ] = "\n\nPlace %s"%widget_type 577 578 self.grid_notebook.dup_source_widget_name = '' # not a dup_widget_label event so no dup_source_widget_name 579 580 581 def Listbox_1_Click(self, event): #click method for component ID=1 582 583 val = 'Button' 584 for i in self.Listbox_1.curselection(): 585 val = self.Listbox_1.get(i)# .lower() 586 self.set_status_msg("Selected Widget: "+self.Listbox_1.get(i) ) 587 588 self.MainWin.placementWidgetType_svar.set(val) 589 590 tab_label = self.grid_notebook.current_tab_label() 591 if not tab_label.startswith('Notebook'): 592 # set duplicate widget text and background to indicate normal placement 593 self.set_placement_widget_label( val ) 594 595 def hideOkChkBox_Callback(self, varName, index, mode): 596 #print( 'Hide OK Button in Dialog =',self.MainWin.hideOkChkBox_StringVar.get(), end="\n") 597 598 try: 599 self.target_app.setSpecialOption('hideokbutton', self.MainWin.hideOkChkBox_StringVar.get()) 600 except: 601 pass 602 603 if self.MainWin.hideOkChkBox_StringVar.get() == "yes": 604 self.PreviewWin.remove_mock_OK_Cancel_Buttons() 605 else: 606 self.PreviewWin.add_mock_OK_Cancel_Buttons() 607 608 def menuChkBox_Callback(self, varName, index, mode): 609 #print( 'make menu =',self.MainWin.menuChkBox_StringVar.get(), end="\n") 610 611 try: 612 self.target_app.setSpecialOption('hasmenu', self.MainWin.menuChkBox_StringVar.get()) 613 #print('Setting Menu "hasmenu" Option To:',self.MainWin.menuChkBox_StringVar.get()) 614 except: 615 print('WARNING... Failed To Properly Set "hasmenu" Option.') 616 617 if not self.in_reading_mode: 618 if self.MainWin.menuChkBox_StringVar.get()=='yes' and self.target_app: 619 dialog = Menumaker(self.MainWin, "Define Menu Structure", 620 self.target_app.getSpecialOption('menu')) 621 #print( dialog.result, end="\n") 622 623 if type(dialog.result) == type({}): 624 625 add_menu_ctrl_keys = dialog.result.get('add_menu_ctrl_keys','yes') 626 self.target_app.setSpecialOption('add_menu_ctrl_keys', add_menu_ctrl_keys) 627 628 menuStr = dialog.result.get('menu','').strip() 629 if len( menuStr ) > 0: 630 self.target_app.setSpecialOption('menu',menuStr) 631 #print( 'Recording new Menu Definition', end="\n") 632 633 634 if not self.PreviewWin: 635 self.refresh_preview_win() # make PreviewWin if not already done. 636 637 # delete menuBar 638 if self.MainWin.menuChkBox_StringVar.get()=='no' and self.target_app: 639 if (self.PreviewWin is not None): 640 if self.PreviewWin.menuBar: 641 self.PreviewWin.delete_menu() 642 643 # create menuBar 644 if self.MainWin.menuChkBox_StringVar.get()=='yes' and self.target_app: 645 if (self.PreviewWin is not None): 646 if self.PreviewWin.menuBar: 647 self.PreviewWin.delete_menu() # delete so menuBar can be recreated 648 649 menuL = buildMenuSource( self.target_app.getSpecialOption( 'menu' ) ) 650 menuSrcL = getMenuSource( menuL, rootName='self' ) 651 652 self.PreviewWin.add_menu( menuSrcL ) 653 654 self.refresh_preview_win() # redraw the form window showing menu state. 655 656 657 def statusBarChkBox_Callback(self, varName, index, mode): 658 #print( 'Status Bar =',self.MainWin.statusBarChkBox_StringVar.get(), end="\n") 659 660 try: 661 self.target_app.setSpecialOption('hasstatusbar', self.MainWin.statusBarChkBox_StringVar.get()) 662 except: 663 pass 664 665 if not self.PreviewWin: 666 self.refresh_preview_win() # make PreviewWin if not already done. 667 668 # add statusbar to PreviewWin 669 if self.MainWin.statusBarChkBox_StringVar.get()=='yes' and self.target_app: 670 if (self.PreviewWin is not None): 671 if not self.PreviewWin.statusbar: 672 self.PreviewWin.add_mock_statusbar() 673 674 # remove statusbar from PreviewWin 675 if self.MainWin.statusBarChkBox_StringVar.get()=='no' and self.target_app: 676 if (self.PreviewWin is not None): 677 if self.PreviewWin.statusbar: 678 self.PreviewWin.remove_mock_statusbar() 679 680 self.refresh_preview_win() # redraw the form window showing menu state. 681 682 def resizableChkBox_Callback(self, varName, index, mode): 683 #print( 'Status Bar =',self.MainWin.resizableChkBox_StringVar.get(), end="\n") 684 685 try: 686 self.target_app.setSpecialOption('resizable', self.MainWin.resizableChkBox_StringVar.get()) 687 except: 688 pass 689 690 self.refresh_preview_win() # redraw the form window showing menu state. 691 692 693 def ColorPickButton_Click(self, event): #put selected color on clipboard 694 self.ColorPickButton_Select() 695 696 def ColorPickButton_Select(self): #put selected color on clipboard 697 self.set_status_msg('Place Selected Color on Clipboard') 698 ctup,cstr = tkinter.colorchooser.askcolor(title='Place Selected Color on Clipboard') 699 if cstr != None: 700 self.set_status_msg('%s is on Clipboard'%cstr) 701 self.ColorPickButton.clipboard_clear() 702 self.ColorPickButton.clipboard_append(cstr) 703 704 #print( 'color chosen=',cstr, end="\n") 705 706 def FontPickButton_Click(self, event): 707 self.FontPickButton_Select() 708 709 def FontPickButton_Select(self): 710 self.set_status_msg('Place Selected Font on Clipboard') 711 font = askfont(self.root) 712 if font: 713 # spaces in the family name need to be escaped 714 font['family'] = font['family'].replace(' ', '\ ') 715 font_str = "%(family)s %(size)i %(weight)s %(slant)s" % font 716 if font['underline']: 717 font_str += ' underline' 718 if font['overstrike']: 719 font_str += ' overstrike' 720 721 self.set_status_msg('%s is on Clipboard'%font_str) 722 self.ColorPickButton.clipboard_clear() 723 self.ColorPickButton.clipboard_append(font_str) 724 725 #print( 'font chosen=',font_str, end="\n") 726 727 728 def Help(self): 729 730 usage = """ 731 732 Basic Usage: 733 Select Widget in Listbox with Left Click. 734 Place Widget with Left Click in grid. 735 736 Edit Widget: 737 Right Click Widget in Grid or Preview Window. 738 739 Move Widget: 740 Left Button Drag and Drop in Grid. 741 742 Duplicate Widget: 743 Left Click Widget in Grid. 744 Left Click in grid to place the duplicate. 745 746 Insert Row or Column with Left Click on "+" control. 747 748 Add Weight to row or column with "wt" control. 749 750 Select Corresponding Tab for Widgets in Frames, RadioGroups etc. 751 """ 752 753 tkinter.messagebox.showinfo( 754 "Help for TkGridGUI", 755 usage) 756 757 def About(self): 758 tkinter.messagebox.showinfo( 759 "About TkGridGUI", 760 "TkGridGUI is:\n\n"+\ 761 "A quick approach to\n"+\ 762 "building Tkinter applications.\n"+\ 763 "Written by Charlie Taylor\n" 764 ) 765 766 def newForm(self): 767 #print( "New Form" ) 768 769 if self.target_app.model_has_changed(): 770 dialog = maybe_save_dialog(self.MainWin, "Save Current File?") 771 772 if (dialog.result is not None) and ( dialog.result['save_file'] == "yes" ): 773 self.saveasFile() 774 return 775 776 self.current_fileFullName = '' # no file for now 777 self.current_filePath = '' # no file for now 778 self.current_fileName = '' # no file for now 779 780 self.MainWin.title( 'TkGridGUI: ' + self.current_fileName ) 781 782 if self.PreviewWin: 783 self.PreviewWin.delete_menu() 784 self.PreviewWin.remove_mock_statusbar() 785 786 self.target_app.reinitialize() 787 self.grid_notebook.initialize_NotebookGridDes() 788 self.grid_notebook.notebook.bind("<<NotebookTabChanged>>", self.tab_of_notebook_changed) 789 790 self.refresh_preview_win() 791 792 # ignore any other warnings 793 self.target_app.reset_crc_reference() # for detecting changes to model 794 795 796 def openFile(self, fName=None): 797 #print( 'Open File' ) 798 799 if self.target_app.model_has_changed(): 800 dialog = maybe_save_dialog(self.MainWin, "Save Current File?") 801 802 if (dialog.result is not None) and (dialog.result['save_file'] == "yes"): 803 self.saveasFile() 804 return 805 else: 806 # ignore any other warnings 807 self.target_app.reset_crc_reference() # for detecting changes to model 808 809 810 self.in_reading_mode = True # when True, suppresses some automatic trace actions. 811 if fName is None: 812 filetypes = [ 813 ('tkGridGUI definition','*.def'), 814 ('Any File','*.*')] 815 self.pathopen = tkinter.filedialog.askopenfilename(parent=self.MainWin, title='Open tkGridGUI file', 816 filetypes=filetypes) 817 #print('self.pathopen =',self.pathopen) 818 else: 819 self.pathopen = os.path.abspath(fName) 820 821 if self.pathopen: 822 823 self.newForm() # clean up any leftovers from another job 824 825 full_fname = os.path.abspath( self.pathopen ) 826 head,tail = os.path.split( full_fname ) 827 828 self.current_fileFullName = full_fname 829 self.current_filePath = head 830 self.current_fileName = tail 831 832 self.target_app.readAppDefFile( self.pathopen ) 833 834 #'hasmenu':'no', 835 self.MainWin.menuChkBox_StringVar.set( self.target_app.getSpecialOption( 'hasmenu' ) ) 836 837 #'hasstatusbar':'no', 838 self.MainWin.statusBarChkBox_StringVar.set( self.target_app.getSpecialOption( 'hasstatusbar' ) ) 839 840 #'resizable':'no' 841 self.MainWin.resizableChkBox_StringVar.set( self.target_app.getSpecialOption( 'resizable' ) ) 842 843 #'hideokbutton':'no' 844 self.MainWin.hideOkChkBox_StringVar.set( self.target_app.getSpecialOption( 'hideokbutton' ) ) 845 846 #'guitype':'main', 847 self.MainWin.mainOrDialog.set( self.target_app.getSpecialOption( 'guitype' ) ) 848 849 #'hasstddialmess':'no', 850 self.MainWin.stdDialMessChkBox_StringVar.set( self.target_app.getSpecialOption( 'hasstddialmess' ) ) 851 852 #'hasstddialcolor':'no', 853 self.MainWin.stdDialColorChkBox_StringVar.set( self.target_app.getSpecialOption( 'hasstddialcolor' ) ) 854 855 #'hasstddialfile':'no', 856 self.MainWin.stdDialFileChkBox_StringVar.set( self.target_app.getSpecialOption( 'hasstddialfile' ) ) 857 858 #'hasstdalarm':'no', 859 self.MainWin.stdAlarmChkBox_StringVar.set( self.target_app.getSpecialOption( 'hasstdalarm' ) ) 860 861 862 #for key,val in self.target_app.app_attrD.items(): 863 # print('%20s %s'%(key, str(val).replace('\t',' '))) 864 865 widgetL = [(c.widget_type, widget_name, c.tab_label, c.row, c.col) for widget_name,c in list(self.target_app.compObjD.items())] 866 self.grid_notebook.set_complete_list_of_widgets( widgetL ) 867 868 if not self.PreviewWin: 869 self.refresh_preview_win() # make PreviewWin if not already done. 870 871 # maybe create menuBar 872 if self.MainWin.menuChkBox_StringVar.get()=='yes' and self.target_app: 873 if (self.PreviewWin is not None): 874 if self.PreviewWin.menuBar: 875 self.PreviewWin.delete_menu() # delete so menuBar can be recreated 876 877 menuL = buildMenuSource( self.target_app.getSpecialOption( 'menu' ) ) 878 menuSrcL = getMenuSource( menuL, rootName='self' ) 879 880 self.PreviewWin.add_menu( menuSrcL ) 881 882 883 # maybe add statusbar to PreviewWin 884 if self.MainWin.statusBarChkBox_StringVar.get()=='yes' and self.target_app: 885 if (self.PreviewWin is not None): 886 if not self.PreviewWin.statusbar: 887 self.PreviewWin.add_mock_statusbar() 888 889 if self.PreviewWin: 890 w = self.target_app.getSpecialOption( 'width' ) 891 h = self.target_app.getSpecialOption( 'height' ) 892 x = self.target_app.getSpecialOption( 'x' ) 893 y = self.target_app.getSpecialOption( 'y' ) 894 895 if self.PreviewWin.statusbar: 896 y += 30 897 898 self.PreviewWin.geometry( '%ix%i+%i+%i'%(w,h,x,y)) 899 #self.PreviewWin.geometry( '' ) # allow to resize after set to x,y 900 self.PreviewWin.update_idletasks() 901 902 self.MainWin.title( 'TkGridGUI: ' + self.current_fileName ) 903 904 self.target_app.reset_crc_reference() # for detecting changes to model 905 906 self.in_reading_mode = False # when True, suppresses some automatic trace actions. 907 908 self.refresh_preview_win() # redraw the form window showing menu state 909 910 self.grid_notebook.notebook.bind("<<NotebookTabChanged>>", self.tab_of_notebook_changed) 911 912 913 914 def saveasFile(self): 915 #print( 'Save File to Disk' ) 916 self.set_status_msg('Save File to Disk') 917 918 filetypes = [ 919 ('TkGridGUI','*.def'), 920 ('Any File','*.*')] 921 922 if self.current_fileName: 923 fname = self.current_fileName 924 else: 925 fname = '' 926 927 928 fsave = tkinter.filedialog.asksaveasfilename(parent=self.MainWin, title='Saving TkGridGUI Definition File', 929 initialfile=fname, filetypes=filetypes) 930 931 if fsave: 932 if not fsave.lower().endswith('.def'): 933 fsave += '.def' 934 935 full_fname = os.path.abspath( fsave ) 936 head,tail = os.path.split( full_fname ) 937 938 self.current_fileFullName = full_fname 939 self.current_filePath = head 940 self.current_fileName = tail 941 942 # set values in target_app 943 944 #'hasmenu':'no', 945 self.target_app.setSpecialOption( 'hasmenu', self.MainWin.menuChkBox_StringVar.get() ) 946 947 #'hasstatusbar':'no', 948 self.target_app.setSpecialOption( 'hasstatusbar' , self.MainWin.statusBarChkBox_StringVar.get() ) 949 950 #'resizable':'no' 951 self.target_app.setSpecialOption( 'resizable', self.MainWin.resizableChkBox_StringVar.get() ) 952 953 #'guitype':'main', 954 self.target_app.setSpecialOption( 'guitype', self.MainWin.mainOrDialog.get() ) 955 956 #'hideokbutton':'no' 957 self.target_app.setSpecialOption( 'hideokbutton', self.MainWin.hideOkChkBox_StringVar.get() ) 958 959 #'hasstddialmess':'no', 960 self.target_app.setSpecialOption( 'hasstddialmess', self.MainWin.stdDialMessChkBox_StringVar.get() ) 961 962 #'hasstddialcolor':'no', 963 self.target_app.setSpecialOption( 'hasstddialcolor', self.MainWin.stdDialColorChkBox_StringVar.get() ) 964 965 #'hasstddialfile':'no', 966 self.target_app.setSpecialOption( 'hasstddialfile', self.MainWin.stdDialFileChkBox_StringVar.get() ) 967 968 #'hasstdalarm':'no', 969 self.target_app.setSpecialOption( 'hasstdalarm', self.MainWin.stdAlarmChkBox_StringVar.get() ) 970 971 # first save *.def file 972 if self.target_app.saveAppDefFile( savePathName=self.current_fileFullName ): 973 # if that goes OK, then save *.py file 974 975 self.MainWin.title( 'TkGridGUI: ' + self.current_fileName ) 976 977 sf = FormSource( self.target_app, self.MainWin, self ) 978 sf.saveToFile() # save *.py file 979 980 981 self.set_status_msg('Saved File: "%s"'%self.current_fileName) 982 983 self.target_app.reset_crc_reference() # for detecting changes to model 984 985 else: 986 self.set_status_msg("WARNING... *.def file save failed. NO SAVE PERFORMED.") 987 988 989 def main(): 990 991 root = Tk() 992 MainWin = root 993 MainWin.title('Main Window') 994 #MainWin.geometry('320x320+10+10') 995 MainWin.config(background='#FFFACD')#'lemonchiffon': '#FFFACD' 996 997 grid_gui = GridGUI( MainWin ) 998 999 MainWin.mainloop() 1000 1001 if __name__=="__main__": 1002 1003 main()