blob: 03475f4060789bf8c114e009a1a841af5920d3cb [file] [log] [blame]
Guido van Rossumf55afae1997-08-12 18:21:21 +00001#
2# An Introduction to Tkinter
3# tkSimpleDialog.py
4#
5# Copyright (c) 1997 by Fredrik Lundh
6#
7# fredrik@pythonware.com
8# http://www.pythonware.com
9#
10
11# --------------------------------------------------------------------
12# dialog base class
13
Guido van Rossumd5062ba2000-02-24 15:01:43 +000014'''Dialog boxes
15
16This module handles dialog boxes. It contains the following
17public symbols:
18
19Dialog -- a base class for dialogs
20
21askinteger -- get an integer from the user
22
23askfloat -- get a float from the user
24
25askstring -- get a string from the user
26'''
27
Guido van Rossumf55afae1997-08-12 18:21:21 +000028from Tkinter import *
29import os
30
31class Dialog(Toplevel):
32
Guido van Rossumd5062ba2000-02-24 15:01:43 +000033 '''Class to open dialogs.
34
35 This class is intended as a base class for custom dialogs
36 '''
37
Guido van Rossumf55afae1997-08-12 18:21:21 +000038 def __init__(self, parent, title = None):
39
Guido van Rossumd5062ba2000-02-24 15:01:43 +000040 '''Initialize a dialog.
41
42 Arguments:
43
44 parent -- a parent window (the application window)
45
46 title -- the dialog title
47 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +000048 Toplevel.__init__(self, parent)
Guido van Rossumf55afae1997-08-12 18:21:21 +000049
Martin v. Löwisc73a4a42006-11-18 18:00:23 +000050 # If the master is not viewable, don't
51 # make the child transient, or else it
52 # would be opened withdrawn
Tim Petersf733abb2007-01-30 03:03:46 +000053 if parent.winfo_viewable():
Martin v. Löwisc73a4a42006-11-18 18:00:23 +000054 self.transient(parent)
Tim Petersf733abb2007-01-30 03:03:46 +000055
Guido van Rossumf55afae1997-08-12 18:21:21 +000056 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
Martin v. Löwisb217cd82004-08-03 18:36:25 +000069 self.wait_visibility() # window needs to be visible for the grab
Guido van Rossumf55afae1997-08-12 18:21:21 +000070 self.grab_set()
71
72 if not self.initial_focus:
73 self.initial_focus = self
74
75 self.protocol("WM_DELETE_WINDOW", self.cancel)
76
Fred Drake6b04ffe2001-12-06 16:51:41 +000077 if self.parent is not None:
78 self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
79 parent.winfo_rooty()+50))
Guido van Rossumf55afae1997-08-12 18:21:21 +000080
81 self.initial_focus.focus_set()
82
83 self.wait_window(self)
84
Guido van Rossum7ea8f841999-06-25 15:53:54 +000085 def destroy(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +000086 '''Destroy the window'''
Guido van Rossum7ea8f841999-06-25 15:53:54 +000087 self.initial_focus = None
88 Toplevel.destroy(self)
89
Guido van Rossumf55afae1997-08-12 18:21:21 +000090 #
91 # construction hooks
92
93 def body(self, master):
Guido van Rossumd5062ba2000-02-24 15:01:43 +000094 '''create dialog body.
Guido van Rossumf55afae1997-08-12 18:21:21 +000095
Fred Draked038ca82000-10-23 18:31:14 +000096 return widget that should have initial focus.
Guido van Rossumd5062ba2000-02-24 15:01:43 +000097 This method should be overridden, and is called
98 by the __init__ method.
99 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000100 pass
101
102 def buttonbox(self):
Fred Draked038ca82000-10-23 18:31:14 +0000103 '''add standard button box.
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000104
Fred Drake6b04ffe2001-12-06 16:51:41 +0000105 override if you do not want the standard buttons
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000106 '''
Fred Draked038ca82000-10-23 18:31:14 +0000107
Guido van Rossumf55afae1997-08-12 18:21:21 +0000108 box = Frame(self)
109
110 w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
111 w.pack(side=LEFT, padx=5, pady=5)
112 w = Button(box, text="Cancel", width=10, command=self.cancel)
113 w.pack(side=LEFT, padx=5, pady=5)
114
115 self.bind("<Return>", self.ok)
116 self.bind("<Escape>", self.cancel)
117
118 box.pack()
119
120 #
121 # standard button semantics
122
123 def ok(self, event=None):
124
125 if not self.validate():
126 self.initial_focus.focus_set() # put focus back
127 return
128
129 self.withdraw()
130 self.update_idletasks()
131
Martin v. Löwisef5fd3e2006-11-18 18:05:35 +0000132 try:
133 self.apply()
134 finally:
135 self.cancel()
Guido van Rossumf55afae1997-08-12 18:21:21 +0000136
137 def cancel(self, event=None):
138
139 # put focus back to the parent window
Fred Drake6b04ffe2001-12-06 16:51:41 +0000140 if self.parent is not None:
141 self.parent.focus_set()
Guido van Rossumf55afae1997-08-12 18:21:21 +0000142 self.destroy()
143
144 #
145 # command hooks
146
147 def validate(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000148 '''validate the data
149
Fred Draked038ca82000-10-23 18:31:14 +0000150 This method is called automatically to validate the data before the
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000151 dialog is destroyed. By default, it always validates OK.
152 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000153
154 return 1 # override
155
156 def apply(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000157 '''process the data
158
159 This method is called automatically to process the data, *after*
160 the dialog is destroyed. By default, it does nothing.
161 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000162
163 pass # override
164
165
166# --------------------------------------------------------------------
167# convenience dialogues
168
Guido van Rossumf55afae1997-08-12 18:21:21 +0000169class _QueryDialog(Dialog):
170
171 def __init__(self, title, prompt,
Guido van Rossum1530c871997-08-14 14:17:28 +0000172 initialvalue=None,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000173 minvalue = None, maxvalue = None,
174 parent = None):
175
Guido van Rossumf55afae1997-08-12 18:21:21 +0000176 if not parent:
Guido van Rossum7f202631998-10-12 20:40:09 +0000177 import Tkinter
178 parent = Tkinter._default_root
Guido van Rossumf55afae1997-08-12 18:21:21 +0000179
180 self.prompt = prompt
181 self.minvalue = minvalue
182 self.maxvalue = maxvalue
183
Guido van Rossum1530c871997-08-14 14:17:28 +0000184 self.initialvalue = initialvalue
185
Guido van Rossumf55afae1997-08-12 18:21:21 +0000186 Dialog.__init__(self, parent, title)
187
Guido van Rossum7ea8f841999-06-25 15:53:54 +0000188 def destroy(self):
189 self.entry = None
190 Dialog.destroy(self)
191
Guido van Rossumf55afae1997-08-12 18:21:21 +0000192 def body(self, master):
193
Guido van Rossum1530c871997-08-14 14:17:28 +0000194 w = Label(master, text=self.prompt, justify=LEFT)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000195 w.grid(row=0, padx=5, sticky=W)
196
197 self.entry = Entry(master, name="entry")
198 self.entry.grid(row=1, padx=5, sticky=W+E)
199
Guido van Rossum1530c871997-08-14 14:17:28 +0000200 if self.initialvalue:
201 self.entry.insert(0, self.initialvalue)
202 self.entry.select_range(0, END)
203
Guido van Rossumf55afae1997-08-12 18:21:21 +0000204 return self.entry
205
206 def validate(self):
207
208 import tkMessageBox
209
210 try:
211 result = self.getresult()
212 except ValueError:
213 tkMessageBox.showwarning(
Guido van Rossum1530c871997-08-14 14:17:28 +0000214 "Illegal value",
Guido van Rossumf55afae1997-08-12 18:21:21 +0000215 self.errormessage + "\nPlease try again",
216 parent = self
217 )
218 return 0
219
220 if self.minvalue is not None and result < self.minvalue:
221 tkMessageBox.showwarning(
222 "Too small",
223 "The allowed minimum value is %s. "
Guido van Rossum1530c871997-08-14 14:17:28 +0000224 "Please try again." % self.minvalue,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000225 parent = self
226 )
227 return 0
228
229 if self.maxvalue is not None and result > self.maxvalue:
230 tkMessageBox.showwarning(
Guido van Rossum1530c871997-08-14 14:17:28 +0000231 "Too large",
Guido van Rossumf55afae1997-08-12 18:21:21 +0000232 "The allowed maximum value is %s. "
Guido van Rossum1530c871997-08-14 14:17:28 +0000233 "Please try again." % self.maxvalue,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000234 parent = self
235 )
236 return 0
Fred Draked038ca82000-10-23 18:31:14 +0000237
Guido van Rossumf55afae1997-08-12 18:21:21 +0000238 self.result = result
239
240 return 1
241
242
243class _QueryInteger(_QueryDialog):
Guido van Rossum1530c871997-08-14 14:17:28 +0000244 errormessage = "Not an integer."
Guido van Rossumf55afae1997-08-12 18:21:21 +0000245 def getresult(self):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000246 return int(self.entry.get())
Guido van Rossumf55afae1997-08-12 18:21:21 +0000247
248def askinteger(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000249 '''get an integer from the user
250
251 Arguments:
252
253 title -- the dialog title
254 prompt -- the label text
255 **kw -- see SimpleDialog class
256
257 Return value is an integer
258 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000259 d = _QueryInteger(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000260 return d.result
261
262class _QueryFloat(_QueryDialog):
Guido van Rossum1530c871997-08-14 14:17:28 +0000263 errormessage = "Not a floating point value."
Guido van Rossumf55afae1997-08-12 18:21:21 +0000264 def getresult(self):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000265 return float(self.entry.get())
Guido van Rossumf55afae1997-08-12 18:21:21 +0000266
267def askfloat(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000268 '''get a float from the user
269
270 Arguments:
271
272 title -- the dialog title
273 prompt -- the label text
274 **kw -- see SimpleDialog class
275
276 Return value is a float
277 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000278 d = _QueryFloat(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000279 return d.result
280
281class _QueryString(_QueryDialog):
Fred Drake6b04ffe2001-12-06 16:51:41 +0000282 def __init__(self, *args, **kw):
283 if kw.has_key("show"):
284 self.__show = kw["show"]
285 del kw["show"]
286 else:
287 self.__show = None
288 _QueryDialog.__init__(self, *args, **kw)
289
290 def body(self, master):
291 entry = _QueryDialog.body(self, master)
292 if self.__show is not None:
293 entry.configure(show=self.__show)
294 return entry
295
Guido van Rossumf55afae1997-08-12 18:21:21 +0000296 def getresult(self):
297 return self.entry.get()
298
299def askstring(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000300 '''get a string from the user
301
302 Arguments:
303
304 title -- the dialog title
305 prompt -- the label text
306 **kw -- see SimpleDialog class
307
308 Return value is a string
309 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000310 d = _QueryString(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000311 return d.result
312
Fred Draked038ca82000-10-23 18:31:14 +0000313if __name__ == "__main__":
Guido van Rossumf55afae1997-08-12 18:21:21 +0000314
315 root = Tk()
316 root.update()
317
Guido van Rossum1530c871997-08-14 14:17:28 +0000318 print askinteger("Spam", "Egg count", initialvalue=12*12)
319 print askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000320 print askstring("Spam", "Egg label")