blob: 15ff544cb63bea8667b23f478cf500e4be81bfde [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)
49 self.transient(parent)
50
51 if title:
52 self.title(title)
53
54 self.parent = parent
55
56 self.result = None
57
58 body = Frame(self)
59 self.initial_focus = self.body(body)
60 body.pack(padx=5, pady=5)
61
62 self.buttonbox()
63
64 self.grab_set()
65
66 if not self.initial_focus:
67 self.initial_focus = self
68
69 self.protocol("WM_DELETE_WINDOW", self.cancel)
70
71 self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
72 parent.winfo_rooty()+50))
73
74 self.initial_focus.focus_set()
75
76 self.wait_window(self)
77
Guido van Rossum7ea8f841999-06-25 15:53:54 +000078 def destroy(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +000079 '''Destroy the window'''
Guido van Rossum7ea8f841999-06-25 15:53:54 +000080 self.initial_focus = None
81 Toplevel.destroy(self)
82
Guido van Rossumf55afae1997-08-12 18:21:21 +000083 #
84 # construction hooks
85
86 def body(self, master):
Guido van Rossumd5062ba2000-02-24 15:01:43 +000087 '''create dialog body.
Guido van Rossumf55afae1997-08-12 18:21:21 +000088
Fred Draked038ca82000-10-23 18:31:14 +000089 return widget that should have initial focus.
Guido van Rossumd5062ba2000-02-24 15:01:43 +000090 This method should be overridden, and is called
91 by the __init__ method.
92 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +000093 pass
94
95 def buttonbox(self):
Fred Draked038ca82000-10-23 18:31:14 +000096 '''add standard button box.
Guido van Rossumd5062ba2000-02-24 15:01:43 +000097
98 override if you don't want the standard buttons
99 '''
Fred Draked038ca82000-10-23 18:31:14 +0000100
Guido van Rossumf55afae1997-08-12 18:21:21 +0000101 box = Frame(self)
102
103 w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
104 w.pack(side=LEFT, padx=5, pady=5)
105 w = Button(box, text="Cancel", width=10, command=self.cancel)
106 w.pack(side=LEFT, padx=5, pady=5)
107
108 self.bind("<Return>", self.ok)
109 self.bind("<Escape>", self.cancel)
110
111 box.pack()
112
113 #
114 # standard button semantics
115
116 def ok(self, event=None):
117
118 if not self.validate():
119 self.initial_focus.focus_set() # put focus back
120 return
121
122 self.withdraw()
123 self.update_idletasks()
124
125 self.apply()
126
127 self.cancel()
128
129 def cancel(self, event=None):
130
131 # put focus back to the parent window
132 self.parent.focus_set()
133 self.destroy()
134
135 #
136 # command hooks
137
138 def validate(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000139 '''validate the data
140
Fred Draked038ca82000-10-23 18:31:14 +0000141 This method is called automatically to validate the data before the
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000142 dialog is destroyed. By default, it always validates OK.
143 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000144
145 return 1 # override
146
147 def apply(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000148 '''process the data
149
150 This method is called automatically to process the data, *after*
151 the dialog is destroyed. By default, it does nothing.
152 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000153
154 pass # override
155
156
157# --------------------------------------------------------------------
158# convenience dialogues
159
Guido van Rossumf55afae1997-08-12 18:21:21 +0000160class _QueryDialog(Dialog):
161
162 def __init__(self, title, prompt,
Guido van Rossum1530c871997-08-14 14:17:28 +0000163 initialvalue=None,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000164 minvalue = None, maxvalue = None,
165 parent = None):
166
Guido van Rossumf55afae1997-08-12 18:21:21 +0000167 if not parent:
Guido van Rossum7f202631998-10-12 20:40:09 +0000168 import Tkinter
169 parent = Tkinter._default_root
Guido van Rossumf55afae1997-08-12 18:21:21 +0000170
171 self.prompt = prompt
172 self.minvalue = minvalue
173 self.maxvalue = maxvalue
174
Guido van Rossum1530c871997-08-14 14:17:28 +0000175 self.initialvalue = initialvalue
176
Guido van Rossumf55afae1997-08-12 18:21:21 +0000177 Dialog.__init__(self, parent, title)
178
Guido van Rossum7ea8f841999-06-25 15:53:54 +0000179 def destroy(self):
180 self.entry = None
181 Dialog.destroy(self)
182
Guido van Rossumf55afae1997-08-12 18:21:21 +0000183 def body(self, master):
184
Guido van Rossum1530c871997-08-14 14:17:28 +0000185 w = Label(master, text=self.prompt, justify=LEFT)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000186 w.grid(row=0, padx=5, sticky=W)
187
188 self.entry = Entry(master, name="entry")
189 self.entry.grid(row=1, padx=5, sticky=W+E)
190
Guido van Rossum1530c871997-08-14 14:17:28 +0000191 if self.initialvalue:
192 self.entry.insert(0, self.initialvalue)
193 self.entry.select_range(0, END)
194
Guido van Rossumf55afae1997-08-12 18:21:21 +0000195 return self.entry
196
197 def validate(self):
198
199 import tkMessageBox
200
201 try:
202 result = self.getresult()
203 except ValueError:
204 tkMessageBox.showwarning(
Guido van Rossum1530c871997-08-14 14:17:28 +0000205 "Illegal value",
Guido van Rossumf55afae1997-08-12 18:21:21 +0000206 self.errormessage + "\nPlease try again",
207 parent = self
208 )
209 return 0
210
211 if self.minvalue is not None and result < self.minvalue:
212 tkMessageBox.showwarning(
213 "Too small",
214 "The allowed minimum value is %s. "
Guido van Rossum1530c871997-08-14 14:17:28 +0000215 "Please try again." % self.minvalue,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000216 parent = self
217 )
218 return 0
219
220 if self.maxvalue is not None and result > self.maxvalue:
221 tkMessageBox.showwarning(
Guido van Rossum1530c871997-08-14 14:17:28 +0000222 "Too large",
Guido van Rossumf55afae1997-08-12 18:21:21 +0000223 "The allowed maximum value is %s. "
Guido van Rossum1530c871997-08-14 14:17:28 +0000224 "Please try again." % self.maxvalue,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000225 parent = self
226 )
227 return 0
Fred Draked038ca82000-10-23 18:31:14 +0000228
Guido van Rossumf55afae1997-08-12 18:21:21 +0000229 self.result = result
230
231 return 1
232
233
234class _QueryInteger(_QueryDialog):
Guido van Rossum1530c871997-08-14 14:17:28 +0000235 errormessage = "Not an integer."
Guido van Rossumf55afae1997-08-12 18:21:21 +0000236 def getresult(self):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000237 return int(self.entry.get())
Guido van Rossumf55afae1997-08-12 18:21:21 +0000238
239def askinteger(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000240 '''get an integer from the user
241
242 Arguments:
243
244 title -- the dialog title
245 prompt -- the label text
246 **kw -- see SimpleDialog class
247
248 Return value is an integer
249 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000250 d = apply(_QueryInteger, (title, prompt), kw)
251 return d.result
252
253class _QueryFloat(_QueryDialog):
Guido van Rossum1530c871997-08-14 14:17:28 +0000254 errormessage = "Not a floating point value."
Guido van Rossumf55afae1997-08-12 18:21:21 +0000255 def getresult(self):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000256 return float(self.entry.get())
Guido van Rossumf55afae1997-08-12 18:21:21 +0000257
258def askfloat(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000259 '''get a float from the user
260
261 Arguments:
262
263 title -- the dialog title
264 prompt -- the label text
265 **kw -- see SimpleDialog class
266
267 Return value is a float
268 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000269 d = apply(_QueryFloat, (title, prompt), kw)
270 return d.result
271
272class _QueryString(_QueryDialog):
273 def getresult(self):
274 return self.entry.get()
275
276def askstring(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000277 '''get a string from the user
278
279 Arguments:
280
281 title -- the dialog title
282 prompt -- the label text
283 **kw -- see SimpleDialog class
284
285 Return value is a string
286 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000287 d = apply(_QueryString, (title, prompt), kw)
288 return d.result
289
Fred Draked038ca82000-10-23 18:31:14 +0000290if __name__ == "__main__":
Guido van Rossumf55afae1997-08-12 18:21:21 +0000291
292 root = Tk()
293 root.update()
294
Guido van Rossum1530c871997-08-14 14:17:28 +0000295 print askinteger("Spam", "Egg count", initialvalue=12*12)
296 print askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000297 print askstring("Spam", "Egg label")