1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
##---------------------------------------------------------------------------##
##
## Python/Tkinter base module/class for a generic dialog
##
## Copyright (C) 1999-2006 Stephen M. Gava
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be of some
## interest to somebody, but WITHOUT ANY WARRANTY; without even the
## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
## See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; see the file COPYING or COPYING.txt. If not,
## write to the Free Software Foundation, Inc.,
## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
## The license can also be found at the GNU/FSF website: http://www.gnu.org
##
## Stephen M. Gava
## <elguavas@users.sourceforge.net>
## http://pyching.sourgeforge.net/elguavas-soft.html
##
##---------------------------------------------------------------------------##
"""
tkinter generic dialog base module
"""
from Tkinter import *
class smgDialog(Toplevel):
"""
tkinter generic dialog, base class
"""
def __init__(self,parent,title=None,buttons=[{'name':'buttonOk','title':'Ok',
'binding':'Ok','underline':None,'hotKey':'<Return>'}],
buttonsDef=-1,buttonsWidth=0,buttonsPad=5,
resizeable=0, transient=1, wait=1): # buttonsPos='BOTTOM',
"""
buttons - a list of button dictionaries, in placement order
keys - 'name' button name, required
'title' button title, required
'binding' button binding, or None
'underline' title character to underline, or None
'hotKey' tkinter key identifier, or None
buttonsDef - position in buttons of default button, or -1 for no default
buttonsWidth - width for all buttons, or 0 for all buttons equal to widest
buttonsPad - pading between buttons, default = 5
resizable, transient, wait - booleans
"""
#buttonsPos - position of button box, 'BOTTOM', 'TOP', 'LEFT' or 'RIGHT'
Toplevel.__init__(self, parent)
self.withdraw()#hide the window until it is fully built
#place the window
self.geometry("+%d+%d" % (parent.winfo_rootx()+10,
parent.winfo_rooty()+10))
#transient window or not
if transient: self.transient(parent)
if resizeable:
self.resizable(height=TRUE,width=TRUE)
else:
self.resizable(height=FALSE,width=FALSE)
if title:
self.title(title)
self.parent = parent
self.result = None
self.frameMain = Frame(self)
#buttons should be created before body in case they are referred to in
#self.Body of a derived class
self.buildButtonBox(buttons, buttonsDef,buttonsWidth, buttonsPad)# buttonsPos,
self.initial_focus = self.Body(self.frameMain)
#self.frameMain.pack(expand=TRUE,fill=BOTH)
self.frameMain.grid(row=0,column=0,sticky=(N,S,E,W))
self.grid_location(0,0)
self.columnconfigure(0,weight=1)
self.rowconfigure(0,weight=1)
#do this after body is packed because it looks better on windoze
self.showButtonBox() #buttonsPos
self.grab_set()
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.Cancel)
self.initial_focus.focus_set()
self.update()
self.deiconify() #unhide the window becuase it's built now
#wait for window to close (modal) or not (non modal)
if wait: self.wait_window(self)
def buildButtonBox(self, buttons, bDef, bWidth, bPad): # bPos,
# add button box
self.frameButtonBox = Frame(self)
bGreatestWidth = 0
bRow = 0
bCol = 0
Num = 0
for button in buttons:
#create button
exec ('self.'+ button['name'] + ' = Button(self.frameButtonBox, text="' +
button['title'] + '",command=self.' + button['binding'] + ')' )
#place button
exec ('self.'+ button['name'] + '.grid(row=' + `bRow` +
', column=' + `bCol` + ', padx=' + `bPad` + ', pady=' + `bPad` + ')' )
#configure optional button hot key
if button['hotKey']:
exec ('self.bind("' + button['hotKey'] + '", self.' + button['binding'] + ')' )
if button['underline']:
exec ('self.'+ button['name'] +
'.configure(underline=' + `button['underline']` + ')' )
#get largest button width so far
wdth = len(button['title']) + 2
if wdth > bGreatestWidth: bGreatestWidth = wdth
# increment row/col
#if bPos in ('BOTTOM','TOP'): #horizontal buttons
# bCol = bCol + 1
#else: #vertical buttons
# bRow = bRow +1
bCol = bCol + 1
#set button widths
if bWidth < bGreatestWidth: bWidth = bGreatestWidth
for button in buttons:
exec ('self.'+ button['name'] +
'.configure(width=' + `bWidth` + ')' )
def showButtonBox(self): #, bPos
#show the button box
#eval('self.frameButtonBox.pack(side=' + bPos + ')' )
self.frameButtonBox.grid(row=1,column=0,sticky=(N,S,E,W))
#
# override this routine in derived classes to define the dialog body
#
def Body(self, master):
# create dialog body and return widget that should have
# initial focus. this method should be overridden
#return initial_focus_widget
pass # override
#
# override these routines in derived classes for Ok button handling
#
def Validate(self):
return 1 # override
def Apply(self):
pass # override
#
# standard button bindings for Ok and Cancel
#
def Ok(self, event=None):
#standard Ok binding
#validate and conditionally close dialog
if not self.Validate(): #if Ok fails validation
self.initial_focus.focus_set() # put focus back
else: #proceed with Ok
self.Apply()
self.Cancel()
def Cancel(self, event=None):
#standard Cancel binding
#close and destroy the dialog
self.update_idletasks()
self.withdraw()
# put focus back to the parent window
self.parent.focus_set()
self.destroy()
|