blob: 573c3a386815d612d76118b041d4d956cd363012 [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 *
Guido van Rossumf55afae1997-08-12 18:21:21 +000029
30class Dialog(Toplevel):
31
Guido van Rossumd5062ba2000-02-24 15:01:43 +000032 '''Class to open dialogs.
33
34 This class is intended as a base class for custom dialogs
35 '''
36
Guido van Rossumf55afae1997-08-12 18:21:21 +000037 def __init__(self, parent, title = None):
38
Guido van Rossumd5062ba2000-02-24 15:01:43 +000039 '''Initialize a dialog.
40
41 Arguments:
42
43 parent -- a parent window (the application window)
44
45 title -- the dialog title
46 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +000047 Toplevel.__init__(self, parent)
Guido van Rossumf55afae1997-08-12 18:21:21 +000048
Thomas Wouters89f507f2006-12-13 04:49:30 +000049 # If the master is not viewable, don't
50 # make the child transient, or else it
51 # would be opened withdrawn
Thomas Wouters9fe394c2007-02-05 01:24:16 +000052 if parent.winfo_viewable():
Thomas Wouters89f507f2006-12-13 04:49:30 +000053 self.transient(parent)
Thomas Wouters9fe394c2007-02-05 01:24:16 +000054
Guido van Rossumf55afae1997-08-12 18:21:21 +000055 if title:
56 self.title(title)
57
58 self.parent = parent
59
60 self.result = None
61
62 body = Frame(self)
63 self.initial_focus = self.body(body)
64 body.pack(padx=5, pady=5)
65
66 self.buttonbox()
67
Martin v. Löwisb217cd82004-08-03 18:36:25 +000068 self.wait_visibility() # window needs to be visible for the grab
Guido van Rossumf55afae1997-08-12 18:21:21 +000069 self.grab_set()
70
71 if not self.initial_focus:
72 self.initial_focus = self
73
74 self.protocol("WM_DELETE_WINDOW", self.cancel)
75
Fred Drake6b04ffe2001-12-06 16:51:41 +000076 if self.parent is not None:
77 self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
78 parent.winfo_rooty()+50))
Guido van Rossumf55afae1997-08-12 18:21:21 +000079
80 self.initial_focus.focus_set()
81
82 self.wait_window(self)
83
Guido van Rossum7ea8f841999-06-25 15:53:54 +000084 def destroy(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +000085 '''Destroy the window'''
Guido van Rossum7ea8f841999-06-25 15:53:54 +000086 self.initial_focus = None
87 Toplevel.destroy(self)
88
Guido van Rossumf55afae1997-08-12 18:21:21 +000089 #
90 # construction hooks
91
92 def body(self, master):
Guido van Rossumd5062ba2000-02-24 15:01:43 +000093 '''create dialog body.
Guido van Rossumf55afae1997-08-12 18:21:21 +000094
Fred Draked038ca82000-10-23 18:31:14 +000095 return widget that should have initial focus.
Guido van Rossumd5062ba2000-02-24 15:01:43 +000096 This method should be overridden, and is called
97 by the __init__ method.
98 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +000099 pass
100
101 def buttonbox(self):
Fred Draked038ca82000-10-23 18:31:14 +0000102 '''add standard button box.
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000103
Fred Drake6b04ffe2001-12-06 16:51:41 +0000104 override if you do not want the standard buttons
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000105 '''
Fred Draked038ca82000-10-23 18:31:14 +0000106
Guido van Rossumf55afae1997-08-12 18:21:21 +0000107 box = Frame(self)
108
109 w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
110 w.pack(side=LEFT, padx=5, pady=5)
111 w = Button(box, text="Cancel", width=10, command=self.cancel)
112 w.pack(side=LEFT, padx=5, pady=5)
113
114 self.bind("<Return>", self.ok)
115 self.bind("<Escape>", self.cancel)
116
117 box.pack()
118
119 #
120 # standard button semantics
121
122 def ok(self, event=None):
123
124 if not self.validate():
125 self.initial_focus.focus_set() # put focus back
126 return
127
128 self.withdraw()
129 self.update_idletasks()
130
Thomas Wouters89f507f2006-12-13 04:49:30 +0000131 try:
132 self.apply()
133 finally:
134 self.cancel()
Guido van Rossumf55afae1997-08-12 18:21:21 +0000135
136 def cancel(self, event=None):
137
138 # put focus back to the parent window
Fred Drake6b04ffe2001-12-06 16:51:41 +0000139 if self.parent is not None:
140 self.parent.focus_set()
Guido van Rossumf55afae1997-08-12 18:21:21 +0000141 self.destroy()
142
143 #
144 # command hooks
145
146 def validate(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000147 '''validate the data
148
Fred Draked038ca82000-10-23 18:31:14 +0000149 This method is called automatically to validate the data before the
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000150 dialog is destroyed. By default, it always validates OK.
151 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000152
153 return 1 # override
154
155 def apply(self):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000156 '''process the data
157
158 This method is called automatically to process the data, *after*
159 the dialog is destroyed. By default, it does nothing.
160 '''
Guido van Rossumf55afae1997-08-12 18:21:21 +0000161
162 pass # override
163
164
165# --------------------------------------------------------------------
166# convenience dialogues
167
Guido van Rossumf55afae1997-08-12 18:21:21 +0000168class _QueryDialog(Dialog):
169
170 def __init__(self, title, prompt,
Guido van Rossum1530c871997-08-14 14:17:28 +0000171 initialvalue=None,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000172 minvalue = None, maxvalue = None,
173 parent = None):
174
Guido van Rossumf55afae1997-08-12 18:21:21 +0000175 if not parent:
Guido van Rossum7f202631998-10-12 20:40:09 +0000176 import Tkinter
177 parent = Tkinter._default_root
Guido van Rossumf55afae1997-08-12 18:21:21 +0000178
179 self.prompt = prompt
180 self.minvalue = minvalue
181 self.maxvalue = maxvalue
182
Guido van Rossum1530c871997-08-14 14:17:28 +0000183 self.initialvalue = initialvalue
184
Guido van Rossumf55afae1997-08-12 18:21:21 +0000185 Dialog.__init__(self, parent, title)
186
Guido van Rossum7ea8f841999-06-25 15:53:54 +0000187 def destroy(self):
188 self.entry = None
189 Dialog.destroy(self)
190
Guido van Rossumf55afae1997-08-12 18:21:21 +0000191 def body(self, master):
192
Guido van Rossum1530c871997-08-14 14:17:28 +0000193 w = Label(master, text=self.prompt, justify=LEFT)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000194 w.grid(row=0, padx=5, sticky=W)
195
196 self.entry = Entry(master, name="entry")
197 self.entry.grid(row=1, padx=5, sticky=W+E)
198
Guido van Rossum1530c871997-08-14 14:17:28 +0000199 if self.initialvalue:
200 self.entry.insert(0, self.initialvalue)
201 self.entry.select_range(0, END)
202
Guido van Rossumf55afae1997-08-12 18:21:21 +0000203 return self.entry
204
205 def validate(self):
206
207 import tkMessageBox
208
209 try:
210 result = self.getresult()
211 except ValueError:
212 tkMessageBox.showwarning(
Guido van Rossum1530c871997-08-14 14:17:28 +0000213 "Illegal value",
Guido van Rossumf55afae1997-08-12 18:21:21 +0000214 self.errormessage + "\nPlease try again",
215 parent = self
216 )
217 return 0
218
219 if self.minvalue is not None and result < self.minvalue:
220 tkMessageBox.showwarning(
221 "Too small",
222 "The allowed minimum value is %s. "
Guido van Rossum1530c871997-08-14 14:17:28 +0000223 "Please try again." % self.minvalue,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000224 parent = self
225 )
226 return 0
227
228 if self.maxvalue is not None and result > self.maxvalue:
229 tkMessageBox.showwarning(
Guido van Rossum1530c871997-08-14 14:17:28 +0000230 "Too large",
Guido van Rossumf55afae1997-08-12 18:21:21 +0000231 "The allowed maximum value is %s. "
Guido van Rossum1530c871997-08-14 14:17:28 +0000232 "Please try again." % self.maxvalue,
Guido van Rossumf55afae1997-08-12 18:21:21 +0000233 parent = self
234 )
235 return 0
Fred Draked038ca82000-10-23 18:31:14 +0000236
Guido van Rossumf55afae1997-08-12 18:21:21 +0000237 self.result = result
238
239 return 1
240
241
242class _QueryInteger(_QueryDialog):
Guido van Rossum1530c871997-08-14 14:17:28 +0000243 errormessage = "Not an integer."
Guido van Rossumf55afae1997-08-12 18:21:21 +0000244 def getresult(self):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000245 return int(self.entry.get())
Guido van Rossumf55afae1997-08-12 18:21:21 +0000246
247def askinteger(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000248 '''get an integer from the user
249
250 Arguments:
251
252 title -- the dialog title
253 prompt -- the label text
254 **kw -- see SimpleDialog class
255
256 Return value is an integer
257 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000258 d = _QueryInteger(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000259 return d.result
260
261class _QueryFloat(_QueryDialog):
Guido van Rossum1530c871997-08-14 14:17:28 +0000262 errormessage = "Not a floating point value."
Guido van Rossumf55afae1997-08-12 18:21:21 +0000263 def getresult(self):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000264 return float(self.entry.get())
Guido van Rossumf55afae1997-08-12 18:21:21 +0000265
266def askfloat(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000267 '''get a float from the user
268
269 Arguments:
270
271 title -- the dialog title
272 prompt -- the label text
273 **kw -- see SimpleDialog class
274
275 Return value is a float
276 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000277 d = _QueryFloat(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000278 return d.result
279
280class _QueryString(_QueryDialog):
Fred Drake6b04ffe2001-12-06 16:51:41 +0000281 def __init__(self, *args, **kw):
Guido van Rossume014a132006-08-19 16:53:45 +0000282 if "show" in kw:
Fred Drake6b04ffe2001-12-06 16:51:41 +0000283 self.__show = kw["show"]
284 del kw["show"]
285 else:
286 self.__show = None
287 _QueryDialog.__init__(self, *args, **kw)
288
289 def body(self, master):
290 entry = _QueryDialog.body(self, master)
291 if self.__show is not None:
292 entry.configure(show=self.__show)
293 return entry
294
Guido van Rossumf55afae1997-08-12 18:21:21 +0000295 def getresult(self):
296 return self.entry.get()
297
298def askstring(title, prompt, **kw):
Guido van Rossumd5062ba2000-02-24 15:01:43 +0000299 '''get a string from the user
300
301 Arguments:
302
303 title -- the dialog title
304 prompt -- the label text
305 **kw -- see SimpleDialog class
306
307 Return value is a string
308 '''
Raymond Hettingerff41c482003-04-06 09:01:11 +0000309 d = _QueryString(title, prompt, **kw)
Guido van Rossumf55afae1997-08-12 18:21:21 +0000310 return d.result
311
Fred Draked038ca82000-10-23 18:31:14 +0000312if __name__ == "__main__":
Guido van Rossumf55afae1997-08-12 18:21:21 +0000313
314 root = Tk()
315 root.update()
316
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000317 print(askinteger("Spam", "Egg count", initialvalue=12*12))
318 print(askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100))
319 print(askstring("Spam", "Egg label"))