Home | History | Annotate | Download | only in lib-tk
      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