1 # 2 # An Introduction to Tkinter 3 # tkSimpleDialog.py 4 # 5 # Copyright (c) 1997 by Fredrik Lundh 6 # 7 # fredrik (at] pythonware.com 8 # http://www.pythonware.com 9 # 10 11 # -------------------------------------------------------------------- 12 # dialog base class 13 14 '''Dialog boxes 15 16 This module handles dialog boxes. It contains the following 17 public symbols: 18 19 Dialog -- a base class for dialogs 20 21 askinteger -- get an integer from the user 22 23 askfloat -- get a float from the user 24 25 askstring -- get a string from the user 26 ''' 27 28 from Tkinter import * 29 30 class Dialog(Toplevel): 31 32 '''Class to open dialogs. 33 34 This class is intended as a base class for custom dialogs 35 ''' 36 37 def __init__(self, parent, title = None): 38 39 '''Initialize a dialog. 40 41 Arguments: 42 43 parent -- a parent window (the application window) 44 45 title -- the dialog title 46 ''' 47 Toplevel.__init__(self, parent) 48 49 self.withdraw() # remain invisible for now 50 # If the master is not viewable, don't 51 # make the child transient, or else it 52 # would be opened withdrawn 53 if parent.winfo_viewable(): 54 self.transient(parent) 55 56 if title: 57 self.title(title) 58 59 self.parent = parent 60 61 self.result = None 62 63 body = Frame(self) 64 self.initial_focus = self.body(body) 65 body.pack(padx=5, pady=5) 66 67 self.buttonbox() 68 69 70 if not self.initial_focus: 71 self.initial_focus = self 72 73 self.protocol("WM_DELETE_WINDOW", self.cancel) 74 75 if self.parent is not None: 76 self.geometry("+%d+%d" % (parent.winfo_rootx()+50, 77 parent.winfo_rooty()+50)) 78 79 self.deiconify() # become visibile now 80 81 self.initial_focus.focus_set() 82 83 # wait for window to appear on screen before calling grab_set 84 self.wait_visibility() 85 self.grab_set() 86 self.wait_window(self) 87 88 def destroy(self): 89 '''Destroy the window''' 90 self.initial_focus = None 91 Toplevel.destroy(self) 92 93 # 94 # construction hooks 95 96 def body(self, master): 97 '''create dialog body. 98 99 return widget that should have initial focus. 100 This method should be overridden, and is called 101 by the __init__ method. 102 ''' 103 pass 104 105 def buttonbox(self): 106 '''add standard button box. 107 108 override if you do not want the standard buttons 109 ''' 110 111 box = Frame(self) 112 113 w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE) 114 w.pack(side=LEFT, padx=5, pady=5) 115 w = Button(box, text="Cancel", width=10, command=self.cancel) 116 w.pack(side=LEFT, padx=5, pady=5) 117 118 self.bind("<Return>", self.ok) 119 self.bind("<Escape>", self.cancel) 120 121 box.pack() 122 123 # 124 # standard button semantics 125 126 def ok(self, event=None): 127 128 if not self.validate(): 129 self.initial_focus.focus_set() # put focus back 130 return 131 132 self.withdraw() 133 self.update_idletasks() 134 135 try: 136 self.apply() 137 finally: 138 self.cancel() 139 140 def cancel(self, event=None): 141 142 # put focus back to the parent window 143 if self.parent is not None: 144 self.parent.focus_set() 145 self.destroy() 146 147 # 148 # command hooks 149 150 def validate(self): 151 '''validate the data 152 153 This method is called automatically to validate the data before the 154 dialog is destroyed. By default, it always validates OK. 155 ''' 156 157 return 1 # override 158 159 def apply(self): 160 '''process the data 161 162 This method is called automatically to process the data, *after* 163 the dialog is destroyed. By default, it does nothing. 164 ''' 165 166 pass # override 167 168 169 # -------------------------------------------------------------------- 170 # convenience dialogues 171 172 class _QueryDialog(Dialog): 173 174 def __init__(self, title, prompt, 175 initialvalue=None, 176 minvalue = None, maxvalue = None, 177 parent = None): 178 179 if not parent: 180 import Tkinter 181 parent = Tkinter._default_root 182 183 self.prompt = prompt 184 self.minvalue = minvalue 185 self.maxvalue = maxvalue 186 187 self.initialvalue = initialvalue 188 189 Dialog.__init__(self, parent, title) 190 191 def destroy(self): 192 self.entry = None 193 Dialog.destroy(self) 194 195 def body(self, master): 196 197 w = Label(master, text=self.prompt, justify=LEFT) 198 w.grid(row=0, padx=5, sticky=W) 199 200 self.entry = Entry(master, name="entry") 201 self.entry.grid(row=1, padx=5, sticky=W+E) 202 203 if self.initialvalue is not None: 204 self.entry.insert(0, self.initialvalue) 205 self.entry.select_range(0, END) 206 207 return self.entry 208 209 def validate(self): 210 211 import tkMessageBox 212 213 try: 214 result = self.getresult() 215 except ValueError: 216 tkMessageBox.showwarning( 217 "Illegal value", 218 self.errormessage + "\nPlease try again", 219 parent = self 220 ) 221 return 0 222 223 if self.minvalue is not None and result < self.minvalue: 224 tkMessageBox.showwarning( 225 "Too small", 226 "The allowed minimum value is %s. " 227 "Please try again." % self.minvalue, 228 parent = self 229 ) 230 return 0 231 232 if self.maxvalue is not None and result > self.maxvalue: 233 tkMessageBox.showwarning( 234 "Too large", 235 "The allowed maximum value is %s. " 236 "Please try again." % self.maxvalue, 237 parent = self 238 ) 239 return 0 240 241 self.result = result 242 243 return 1 244 245 246 class _QueryInteger(_QueryDialog): 247 errormessage = "Not an integer." 248 def getresult(self): 249 return int(self.entry.get()) 250 251 def askinteger(title, prompt, **kw): 252 '''get an integer from the user 253 254 Arguments: 255 256 title -- the dialog title 257 prompt -- the label text 258 **kw -- see SimpleDialog class 259 260 Return value is an integer 261 ''' 262 d = _QueryInteger(title, prompt, **kw) 263 return d.result 264 265 class _QueryFloat(_QueryDialog): 266 errormessage = "Not a floating point value." 267 def getresult(self): 268 return float(self.entry.get()) 269 270 def askfloat(title, prompt, **kw): 271 '''get a float from the user 272 273 Arguments: 274 275 title -- the dialog title 276 prompt -- the label text 277 **kw -- see SimpleDialog class 278 279 Return value is a float 280 ''' 281 d = _QueryFloat(title, prompt, **kw) 282 return d.result 283 284 class _QueryString(_QueryDialog): 285 def __init__(self, *args, **kw): 286 if "show" in kw: 287 self.__show = kw["show"] 288 del kw["show"] 289 else: 290 self.__show = None 291 _QueryDialog.__init__(self, *args, **kw) 292 293 def body(self, master): 294 entry = _QueryDialog.body(self, master) 295 if self.__show is not None: 296 entry.configure(show=self.__show) 297 return entry 298 299 def getresult(self): 300 return self.entry.get() 301 302 def askstring(title, prompt, **kw): 303 '''get a string from the user 304 305 Arguments: 306 307 title -- the dialog title 308 prompt -- the label text 309 **kw -- see SimpleDialog class 310 311 Return value is a string 312 ''' 313 d = _QueryString(title, prompt, **kw) 314 return d.result 315 316 if __name__ == "__main__": 317 318 root = Tk() 319 root.update() 320 321 print askinteger("Spam", "Egg count", initialvalue=12*12) 322 print askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100) 323 print askstring("Spam", "Egg label") 324