Viewing file: simpledialog.py (11.14 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# # An Introduction to Tkinter # # Copyright (c) 1997 by Fredrik Lundh # # This copyright applies to Dialog, askinteger, askfloat and asktring # # fredrik@pythonware.com # http://www.pythonware.com # """This modules handles dialog boxes.
It contains the following public symbols:
SimpleDialog -- A simple but flexible modal dialog box
Dialog -- a base class for dialogs
askinteger -- get an integer from the user
askfloat -- get a float from the user
askstring -- get a string from the user """
from tkinter import * from tkinter import messagebox
import tkinter # used at _QueryDialog for tkinter._default_root
class SimpleDialog:
def __init__(self, master, text='', buttons=[], default=None, cancel=None, title=None, class_=None): if class_: self.root = Toplevel(master, class_=class_) else: self.root = Toplevel(master) if title: self.root.title(title) self.root.iconname(title) self.message = Message(self.root, text=text, aspect=400) self.message.pack(expand=1, fill=BOTH) self.frame = Frame(self.root) self.frame.pack() self.num = default self.cancel = cancel self.default = default self.root.bind('<Return>', self.return_event) for num in range(len(buttons)): s = buttons[num] b = Button(self.frame, text=s, command=(lambda self=self, num=num: self.done(num))) if num == default: b.config(relief=RIDGE, borderwidth=8) b.pack(side=LEFT, fill=BOTH, expand=1) self.root.protocol('WM_DELETE_WINDOW', self.wm_delete_window) self._set_transient(master)
def _set_transient(self, master, relx=0.5, rely=0.3): widget = self.root widget.withdraw() # Remain invisible while we figure out the geometry widget.transient(master) widget.update_idletasks() # Actualize geometry information if master.winfo_ismapped(): m_width = master.winfo_width() m_height = master.winfo_height() m_x = master.winfo_rootx() m_y = master.winfo_rooty() else: m_width = master.winfo_screenwidth() m_height = master.winfo_screenheight() m_x = m_y = 0 w_width = widget.winfo_reqwidth() w_height = widget.winfo_reqheight() x = m_x + (m_width - w_width) * relx y = m_y + (m_height - w_height) * rely if x+w_width > master.winfo_screenwidth(): x = master.winfo_screenwidth() - w_width elif x < 0: x = 0 if y+w_height > master.winfo_screenheight(): y = master.winfo_screenheight() - w_height elif y < 0: y = 0 widget.geometry("+%d+%d" % (x, y)) widget.deiconify() # Become visible at the desired location
def go(self): self.root.wait_visibility() self.root.grab_set() self.root.mainloop() self.root.destroy() return self.num
def return_event(self, event): if self.default is None: self.root.bell() else: self.done(self.default)
def wm_delete_window(self): if self.cancel is None: self.root.bell() else: self.done(self.cancel)
def done(self, num): self.num = num self.root.quit()
class Dialog(Toplevel):
'''Class to open dialogs.
This class is intended as a base class for custom dialogs '''
def __init__(self, parent, title = None):
'''Initialize a dialog.
Arguments:
parent -- a parent window (the application window)
title -- the dialog title ''' Toplevel.__init__(self, parent)
self.withdraw() # remain invisible for now # If the master is not viewable, don't # make the child transient, or else it # would be opened withdrawn if parent.winfo_viewable(): self.transient(parent)
if title: self.title(title)
self.parent = parent
self.result = None
body = Frame(self) self.initial_focus = self.body(body) body.pack(padx=5, pady=5)
self.buttonbox()
if not self.initial_focus: self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
if self.parent is not None: self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))
self.deiconify() # become visible now
self.initial_focus.focus_set()
# wait for window to appear on screen before calling grab_set self.wait_visibility() self.grab_set() self.wait_window(self)
def destroy(self): '''Destroy the window''' self.initial_focus = None Toplevel.destroy(self)
# # construction hooks
def body(self, master): '''create dialog body.
return widget that should have initial focus. This method should be overridden, and is called by the __init__ method. ''' pass
def buttonbox(self): '''add standard button box.
override if you do not want the standard buttons '''
box = Frame(self)
w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE) w.pack(side=LEFT, padx=5, pady=5) w = Button(box, text="Cancel", width=10, command=self.cancel) w.pack(side=LEFT, padx=5, pady=5)
self.bind("<Return>", self.ok) self.bind("<Escape>", self.cancel)
box.pack()
# # standard button semantics
def ok(self, event=None):
if not self.validate(): self.initial_focus.focus_set() # put focus back return
self.withdraw() self.update_idletasks()
try: self.apply() finally: self.cancel()
def cancel(self, event=None):
# put focus back to the parent window if self.parent is not None: self.parent.focus_set() self.destroy()
# # command hooks
def validate(self): '''validate the data
This method is called automatically to validate the data before the dialog is destroyed. By default, it always validates OK. '''
return 1 # override
def apply(self): '''process the data
This method is called automatically to process the data, *after* the dialog is destroyed. By default, it does nothing. '''
pass # override
# -------------------------------------------------------------------- # convenience dialogues
class _QueryDialog(Dialog):
def __init__(self, title, prompt, initialvalue=None, minvalue = None, maxvalue = None, parent = None):
if not parent: parent = tkinter._default_root
self.prompt = prompt self.minvalue = minvalue self.maxvalue = maxvalue
self.initialvalue = initialvalue
Dialog.__init__(self, parent, title)
def destroy(self): self.entry = None Dialog.destroy(self)
def body(self, master):
w = Label(master, text=self.prompt, justify=LEFT) w.grid(row=0, padx=5, sticky=W)
self.entry = Entry(master, name="entry") self.entry.grid(row=1, padx=5, sticky=W+E)
if self.initialvalue is not None: self.entry.insert(0, self.initialvalue) self.entry.select_range(0, END)
return self.entry
def validate(self): try: result = self.getresult() except ValueError: messagebox.showwarning( "Illegal value", self.errormessage + "\nPlease try again", parent = self ) return 0
if self.minvalue is not None and result < self.minvalue: messagebox.showwarning( "Too small", "The allowed minimum value is %s. " "Please try again." % self.minvalue, parent = self ) return 0
if self.maxvalue is not None and result > self.maxvalue: messagebox.showwarning( "Too large", "The allowed maximum value is %s. " "Please try again." % self.maxvalue, parent = self ) return 0
self.result = result
return 1
class _QueryInteger(_QueryDialog): errormessage = "Not an integer." def getresult(self): return int(self.entry.get())
def askinteger(title, prompt, **kw): '''get an integer from the user
Arguments:
title -- the dialog title prompt -- the label text **kw -- see SimpleDialog class
Return value is an integer ''' d = _QueryInteger(title, prompt, **kw) return d.result
class _QueryFloat(_QueryDialog): errormessage = "Not a floating point value." def getresult(self): return float(self.entry.get())
def askfloat(title, prompt, **kw): '''get a float from the user
Arguments:
title -- the dialog title prompt -- the label text **kw -- see SimpleDialog class
Return value is a float ''' d = _QueryFloat(title, prompt, **kw) return d.result
class _QueryString(_QueryDialog): def __init__(self, *args, **kw): if "show" in kw: self.__show = kw["show"] del kw["show"] else: self.__show = None _QueryDialog.__init__(self, *args, **kw)
def body(self, master): entry = _QueryDialog.body(self, master) if self.__show is not None: entry.configure(show=self.__show) return entry
def getresult(self): return self.entry.get()
def askstring(title, prompt, **kw): '''get a string from the user
Arguments:
title -- the dialog title prompt -- the label text **kw -- see SimpleDialog class
Return value is a string ''' d = _QueryString(title, prompt, **kw) return d.result
if __name__ == '__main__':
def test(): root = Tk() def doit(root=root): d = SimpleDialog(root, text="This is a test dialog. " "Would this have been an actual dialog, " "the buttons below would have been glowing " "in soft pink light.\n" "Do you believe this?", buttons=["Yes", "No", "Cancel"], default=0, cancel=2, title="Test Dialog") print(d.go()) print(askinteger("Spam", "Egg count", initialvalue=12*12)) print(askfloat("Spam", "Egg weight\n(in tons)", minvalue=1, maxvalue=100)) print(askstring("Spam", "Egg label")) t = Button(root, text='Test', command=doit) t.pack() q = Button(root, text='Quit', command=t.quit) q.pack() t.mainloop()
test()
|