Back to index

python3.2  3.2.2
ttk.py
Go to the documentation of this file.
00001 """Ttk wrapper.
00002 
00003 This module provides classes to allow using Tk themed widget set.
00004 
00005 Ttk is based on a revised and enhanced version of
00006 TIP #48 (http://tip.tcl.tk/48) specified style engine.
00007 
00008 Its basic idea is to separate, to the extent possible, the code
00009 implementing a widget's behavior from the code implementing its
00010 appearance. Widget class bindings are primarily responsible for
00011 maintaining the widget state and invoking callbacks, all aspects
00012 of the widgets appearance lies at Themes.
00013 """
00014 
00015 __version__ = "0.3.1"
00016 
00017 __author__ = "Guilherme Polo <ggpolo@gmail.com>"
00018 
00019 __all__ = ["Button", "Checkbutton", "Combobox", "Entry", "Frame", "Label",
00020            "Labelframe", "LabelFrame", "Menubutton", "Notebook", "Panedwindow",
00021            "PanedWindow", "Progressbar", "Radiobutton", "Scale", "Scrollbar",
00022            "Separator", "Sizegrip", "Style", "Treeview",
00023            # Extensions
00024            "LabeledScale", "OptionMenu",
00025            # functions
00026            "tclobjs_to_py", "setup_master"]
00027 
00028 import tkinter
00029 
00030 _flatten = tkinter._flatten
00031 
00032 # Verify if Tk is new enough to not need the Tile package
00033 _REQUIRE_TILE = True if tkinter.TkVersion < 8.5 else False
00034 
00035 def _load_tile(master):
00036     if _REQUIRE_TILE:
00037         import os
00038         tilelib = os.environ.get('TILE_LIBRARY')
00039         if tilelib:
00040             # append custom tile path to the the list of directories that
00041             # Tcl uses when attempting to resolve packages with the package
00042             # command
00043             master.tk.eval(
00044                     'global auto_path; '
00045                     'lappend auto_path {%s}' % tilelib)
00046 
00047         master.tk.eval('package require tile') # TclError may be raised here
00048         master._tile_loaded = True
00049 
00050 def _format_optdict(optdict, script=False, ignore=None):
00051     """Formats optdict to a tuple to pass it to tk.call.
00052 
00053     E.g. (script=False):
00054       {'foreground': 'blue', 'padding': [1, 2, 3, 4]} returns:
00055       ('-foreground', 'blue', '-padding', '1 2 3 4')"""
00056     format = "%s" if not script else "{%s}"
00057 
00058     opts = []
00059     for opt, value in optdict.items():
00060         if ignore and opt in ignore:
00061             continue
00062 
00063         if isinstance(value, (list, tuple)):
00064             v = []
00065             for val in value:
00066                 if isinstance(val, str):
00067                     v.append(str(val) if val else '{}')
00068                 else:
00069                     v.append(str(val))
00070 
00071             # format v according to the script option, but also check for
00072             # space in any value in v in order to group them correctly
00073             value = format % ' '.join(
00074                 ('{%s}' if ' ' in val else '%s') % val for val in v)
00075 
00076         if script and value == '':
00077             value = '{}' # empty string in Python is equivalent to {} in Tcl
00078 
00079         opts.append(("-%s" % opt, value))
00080 
00081     # Remember: _flatten skips over None
00082     return _flatten(opts)
00083 
00084 def _format_mapdict(mapdict, script=False):
00085     """Formats mapdict to pass it to tk.call.
00086 
00087     E.g. (script=False):
00088       {'expand': [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]}
00089 
00090       returns:
00091 
00092       ('-expand', '{active selected} grey focus {1, 2, 3, 4}')"""
00093     # if caller passes a Tcl script to tk.call, all the values need to
00094     # be grouped into words (arguments to a command in Tcl dialect)
00095     format = "%s" if not script else "{%s}"
00096 
00097     opts = []
00098     for opt, value in mapdict.items():
00099 
00100         opt_val = []
00101         # each value in mapdict is expected to be a sequence, where each item
00102         # is another sequence containing a state (or several) and a value
00103         for statespec in value:
00104             state, val = statespec[:-1], statespec[-1]
00105 
00106             if len(state) > 1: # group multiple states
00107                 state = "{%s}" % ' '.join(state)
00108             else: # single state
00109                 # if it is empty (something that evaluates to False), then
00110                 # format it to Tcl code to denote the "normal" state
00111                 state = state[0] or '{}'
00112 
00113             if isinstance(val, (list, tuple)): # val needs to be grouped
00114                 val = "{%s}" % ' '.join(map(str, val))
00115 
00116             opt_val.append("%s %s" % (state, val))
00117 
00118         opts.append(("-%s" % opt, format % ' '.join(opt_val)))
00119 
00120     return _flatten(opts)
00121 
00122 def _format_elemcreate(etype, script=False, *args, **kw):
00123     """Formats args and kw according to the given element factory etype."""
00124     spec = None
00125     opts = ()
00126     if etype in ("image", "vsapi"):
00127         if etype == "image": # define an element based on an image
00128             # first arg should be the default image name
00129             iname = args[0]
00130             # next args, if any, are statespec/value pairs which is almost
00131             # a mapdict, but we just need the value
00132             imagespec = _format_mapdict({None: args[1:]})[1]
00133             spec = "%s %s" % (iname, imagespec)
00134 
00135         else:
00136             # define an element whose visual appearance is drawn using the
00137             # Microsoft Visual Styles API which is responsible for the
00138             # themed styles on Windows XP and Vista.
00139             # Availability: Tk 8.6, Windows XP and Vista.
00140             class_name, part_id = args[:2]
00141             statemap = _format_mapdict({None: args[2:]})[1]
00142             spec = "%s %s %s" % (class_name, part_id, statemap)
00143 
00144         opts = _format_optdict(kw, script)
00145 
00146     elif etype == "from": # clone an element
00147         # it expects a themename and optionally an element to clone from,
00148         # otherwise it will clone {} (empty element)
00149         spec = args[0] # theme name
00150         if len(args) > 1: # elementfrom specified
00151             opts = (args[1], )
00152 
00153     if script:
00154         spec = '{%s}' % spec
00155         opts = ' '.join(map(str, opts))
00156 
00157     return spec, opts
00158 
00159 def _format_layoutlist(layout, indent=0, indent_size=2):
00160     """Formats a layout list so we can pass the result to ttk::style
00161     layout and ttk::style settings. Note that the layout doesn't has to
00162     be a list necessarily.
00163 
00164     E.g.:
00165       [("Menubutton.background", None),
00166        ("Menubutton.button", {"children":
00167            [("Menubutton.focus", {"children":
00168                [("Menubutton.padding", {"children":
00169                 [("Menubutton.label", {"side": "left", "expand": 1})]
00170                })]
00171            })]
00172        }),
00173        ("Menubutton.indicator", {"side": "right"})
00174       ]
00175 
00176       returns:
00177 
00178       Menubutton.background
00179       Menubutton.button -children {
00180         Menubutton.focus -children {
00181           Menubutton.padding -children {
00182             Menubutton.label -side left -expand 1
00183           }
00184         }
00185       }
00186       Menubutton.indicator -side right"""
00187     script = []
00188 
00189     for layout_elem in layout:
00190         elem, opts = layout_elem
00191         opts = opts or {}
00192         fopts = ' '.join(map(str, _format_optdict(opts, True, "children")))
00193         head = "%s%s%s" % (' ' * indent, elem, (" %s" % fopts) if fopts else '')
00194 
00195         if "children" in opts:
00196             script.append(head + " -children {")
00197             indent += indent_size
00198             newscript, indent = _format_layoutlist(opts['children'], indent,
00199                 indent_size)
00200             script.append(newscript)
00201             indent -= indent_size
00202             script.append('%s}' % (' ' * indent))
00203         else:
00204             script.append(head)
00205 
00206     return '\n'.join(script), indent
00207 
00208 def _script_from_settings(settings):
00209     """Returns an appropriate script, based on settings, according to
00210     theme_settings definition to be used by theme_settings and
00211     theme_create."""
00212     script = []
00213     # a script will be generated according to settings passed, which
00214     # will then be evaluated by Tcl
00215     for name, opts in settings.items():
00216         # will format specific keys according to Tcl code
00217         if opts.get('configure'): # format 'configure'
00218             s = ' '.join(map(str, _format_optdict(opts['configure'], True)))
00219             script.append("ttk::style configure %s %s;" % (name, s))
00220 
00221         if opts.get('map'): # format 'map'
00222             s = ' '.join(map(str, _format_mapdict(opts['map'], True)))
00223             script.append("ttk::style map %s %s;" % (name, s))
00224 
00225         if 'layout' in opts: # format 'layout' which may be empty
00226             if not opts['layout']:
00227                 s = 'null' # could be any other word, but this one makes sense
00228             else:
00229                 s, _ = _format_layoutlist(opts['layout'])
00230             script.append("ttk::style layout %s {\n%s\n}" % (name, s))
00231 
00232         if opts.get('element create'): # format 'element create'
00233             eopts = opts['element create']
00234             etype = eopts[0]
00235 
00236             # find where args end, and where kwargs start
00237             argc = 1 # etype was the first one
00238             while argc < len(eopts) and not hasattr(eopts[argc], 'items'):
00239                 argc += 1
00240 
00241             elemargs = eopts[1:argc]
00242             elemkw = eopts[argc] if argc < len(eopts) and eopts[argc] else {}
00243             spec, opts = _format_elemcreate(etype, True, *elemargs, **elemkw)
00244 
00245             script.append("ttk::style element create %s %s %s %s" % (
00246                 name, etype, spec, opts))
00247 
00248     return '\n'.join(script)
00249 
00250 def _dict_from_tcltuple(ttuple, cut_minus=True):
00251     """Break tuple in pairs, format it properly, then build the return
00252     dict. If cut_minus is True, the supposed '-' prefixing options will
00253     be removed.
00254 
00255     ttuple is expected to contain an even number of elements."""
00256     opt_start = 1 if cut_minus else 0
00257 
00258     retdict = {}
00259     it = iter(ttuple)
00260     for opt, val in zip(it, it):
00261         retdict[str(opt)[opt_start:]] = val
00262 
00263     return tclobjs_to_py(retdict)
00264 
00265 def _list_from_statespec(stuple):
00266     """Construct a list from the given statespec tuple according to the
00267     accepted statespec accepted by _format_mapdict."""
00268     nval = []
00269     for val in stuple:
00270         typename = getattr(val, 'typename', None)
00271         if typename is None:
00272             nval.append(val)
00273         else: # this is a Tcl object
00274             val = str(val)
00275             if typename == 'StateSpec':
00276                 val = val.split()
00277             nval.append(val)
00278 
00279     it = iter(nval)
00280     return [_flatten(spec) for spec in zip(it, it)]
00281 
00282 def _list_from_layouttuple(ltuple):
00283     """Construct a list from the tuple returned by ttk::layout, this is
00284     somewhat the reverse of _format_layoutlist."""
00285     res = []
00286 
00287     indx = 0
00288     while indx < len(ltuple):
00289         name = ltuple[indx]
00290         opts = {}
00291         res.append((name, opts))
00292         indx += 1
00293 
00294         while indx < len(ltuple): # grab name's options
00295             opt, val = ltuple[indx:indx + 2]
00296             if not opt.startswith('-'): # found next name
00297                 break
00298 
00299             opt = opt[1:] # remove the '-' from the option
00300             indx += 2
00301 
00302             if opt == 'children':
00303                 val = _list_from_layouttuple(val)
00304 
00305             opts[opt] = val
00306 
00307     return res
00308 
00309 def _val_or_dict(options, func, *args):
00310     """Format options then call func with args and options and return
00311     the appropriate result.
00312 
00313     If no option is specified, a dict is returned. If a option is
00314     specified with the None value, the value for that option is returned.
00315     Otherwise, the function just sets the passed options and the caller
00316     shouldn't be expecting a return value anyway."""
00317     options = _format_optdict(options)
00318     res = func(*(args + options))
00319 
00320     if len(options) % 2: # option specified without a value, return its value
00321         return res
00322 
00323     return _dict_from_tcltuple(res)
00324 
00325 def _convert_stringval(value):
00326     """Converts a value to, hopefully, a more appropriate Python object."""
00327     value = str(value)
00328     try:
00329         value = int(value)
00330     except (ValueError, TypeError):
00331         pass
00332 
00333     return value
00334 
00335 def tclobjs_to_py(adict):
00336     """Returns adict with its values converted from Tcl objects to Python
00337     objects."""
00338     for opt, val in adict.items():
00339         if val and hasattr(val, '__len__') and not isinstance(val, str):
00340             if getattr(val[0], 'typename', None) == 'StateSpec':
00341                 val = _list_from_statespec(val)
00342             else:
00343                 val = list(map(_convert_stringval, val))
00344 
00345         elif hasattr(val, 'typename'): # some other (single) Tcl object
00346             val = _convert_stringval(val)
00347 
00348         adict[opt] = val
00349 
00350     return adict
00351 
00352 def setup_master(master=None):
00353     """If master is not None, itself is returned. If master is None,
00354     the default master is returned if there is one, otherwise a new
00355     master is created and returned.
00356 
00357     If it is not allowed to use the default root and master is None,
00358     RuntimeError is raised."""
00359     if master is None:
00360         if tkinter._support_default_root:
00361             master = tkinter._default_root or tkinter.Tk()
00362         else:
00363             raise RuntimeError(
00364                     "No master specified and tkinter is "
00365                     "configured to not support default root")
00366     return master
00367 
00368 
00369 class Style(object):
00370     """Manipulate style database."""
00371 
00372     _name = "ttk::style"
00373 
00374     def __init__(self, master=None):
00375         master = setup_master(master)
00376 
00377         if not getattr(master, '_tile_loaded', False):
00378             # Load tile now, if needed
00379             _load_tile(master)
00380 
00381         self.master = master
00382         self.tk = self.master.tk
00383 
00384 
00385     def configure(self, style, query_opt=None, **kw):
00386         """Query or sets the default value of the specified option(s) in
00387         style.
00388 
00389         Each key in kw is an option and each value is either a string or
00390         a sequence identifying the value for that option."""
00391         if query_opt is not None:
00392             kw[query_opt] = None
00393         return _val_or_dict(kw, self.tk.call, self._name, "configure", style)
00394 
00395 
00396     def map(self, style, query_opt=None, **kw):
00397         """Query or sets dynamic values of the specified option(s) in
00398         style.
00399 
00400         Each key in kw is an option and each value should be a list or a
00401         tuple (usually) containing statespecs grouped in tuples, or list,
00402         or something else of your preference. A statespec is compound of
00403         one or more states and then a value."""
00404         if query_opt is not None:
00405             return _list_from_statespec(
00406                 self.tk.call(self._name, "map", style, '-%s' % query_opt))
00407 
00408         return _dict_from_tcltuple(
00409             self.tk.call(self._name, "map", style, *(_format_mapdict(kw))))
00410 
00411 
00412     def lookup(self, style, option, state=None, default=None):
00413         """Returns the value specified for option in style.
00414 
00415         If state is specified it is expected to be a sequence of one
00416         or more states. If the default argument is set, it is used as
00417         a fallback value in case no specification for option is found."""
00418         state = ' '.join(state) if state else ''
00419 
00420         return self.tk.call(self._name, "lookup", style, '-%s' % option,
00421             state, default)
00422 
00423 
00424     def layout(self, style, layoutspec=None):
00425         """Define the widget layout for given style. If layoutspec is
00426         omitted, return the layout specification for given style.
00427 
00428         layoutspec is expected to be a list or an object different than
00429         None that evaluates to False if you want to "turn off" that style.
00430         If it is a list (or tuple, or something else), each item should be
00431         a tuple where the first item is the layout name and the second item
00432         should have the format described below:
00433 
00434         LAYOUTS
00435 
00436             A layout can contain the value None, if takes no options, or
00437             a dict of options specifying how to arrange the element.
00438             The layout mechanism uses a simplified version of the pack
00439             geometry manager: given an initial cavity, each element is
00440             allocated a parcel. Valid options/values are:
00441 
00442                 side: whichside
00443                     Specifies which side of the cavity to place the
00444                     element; one of top, right, bottom or left. If
00445                     omitted, the element occupies the entire cavity.
00446 
00447                 sticky: nswe
00448                     Specifies where the element is placed inside its
00449                     allocated parcel.
00450 
00451                 children: [sublayout... ]
00452                     Specifies a list of elements to place inside the
00453                     element. Each element is a tuple (or other sequence)
00454                     where the first item is the layout name, and the other
00455                     is a LAYOUT."""
00456         lspec = None
00457         if layoutspec:
00458             lspec = _format_layoutlist(layoutspec)[0]
00459         elif layoutspec is not None: # will disable the layout ({}, '', etc)
00460             lspec = "null" # could be any other word, but this may make sense
00461                            # when calling layout(style) later
00462 
00463         return _list_from_layouttuple(
00464             self.tk.call(self._name, "layout", style, lspec))
00465 
00466 
00467     def element_create(self, elementname, etype, *args, **kw):
00468         """Create a new element in the current theme of given etype."""
00469         spec, opts = _format_elemcreate(etype, False, *args, **kw)
00470         self.tk.call(self._name, "element", "create", elementname, etype,
00471             spec, *opts)
00472 
00473 
00474     def element_names(self):
00475         """Returns the list of elements defined in the current theme."""
00476         return self.tk.call(self._name, "element", "names")
00477 
00478 
00479     def element_options(self, elementname):
00480         """Return the list of elementname's options."""
00481         return self.tk.call(self._name, "element", "options", elementname)
00482 
00483 
00484     def theme_create(self, themename, parent=None, settings=None):
00485         """Creates a new theme.
00486 
00487         It is an error if themename already exists. If parent is
00488         specified, the new theme will inherit styles, elements and
00489         layouts from the specified parent theme. If settings are present,
00490         they are expected to have the same syntax used for theme_settings."""
00491         script = _script_from_settings(settings) if settings else ''
00492 
00493         if parent:
00494             self.tk.call(self._name, "theme", "create", themename,
00495                 "-parent", parent, "-settings", script)
00496         else:
00497             self.tk.call(self._name, "theme", "create", themename,
00498                 "-settings", script)
00499 
00500 
00501     def theme_settings(self, themename, settings):
00502         """Temporarily sets the current theme to themename, apply specified
00503         settings and then restore the previous theme.
00504 
00505         Each key in settings is a style and each value may contain the
00506         keys 'configure', 'map', 'layout' and 'element create' and they
00507         are expected to have the same format as specified by the methods
00508         configure, map, layout and element_create respectively."""
00509         script = _script_from_settings(settings)
00510         self.tk.call(self._name, "theme", "settings", themename, script)
00511 
00512 
00513     def theme_names(self):
00514         """Returns a list of all known themes."""
00515         return self.tk.call(self._name, "theme", "names")
00516 
00517 
00518     def theme_use(self, themename=None):
00519         """If themename is None, returns the theme in use, otherwise, set
00520         the current theme to themename, refreshes all widgets and emits
00521         a <<ThemeChanged>> event."""
00522         if themename is None:
00523             # Starting on Tk 8.6, checking this global is no longer needed
00524             # since it allows doing self.tk.call(self._name, "theme", "use")
00525             return self.tk.eval("return $ttk::currentTheme")
00526 
00527         # using "ttk::setTheme" instead of "ttk::style theme use" causes
00528         # the variable currentTheme to be updated, also, ttk::setTheme calls
00529         # "ttk::style theme use" in order to change theme.
00530         self.tk.call("ttk::setTheme", themename)
00531 
00532 
00533 class Widget(tkinter.Widget):
00534     """Base class for Tk themed widgets."""
00535 
00536     def __init__(self, master, widgetname, kw=None):
00537         """Constructs a Ttk Widget with the parent master.
00538 
00539         STANDARD OPTIONS
00540 
00541             class, cursor, takefocus, style
00542 
00543         SCROLLABLE WIDGET OPTIONS
00544 
00545             xscrollcommand, yscrollcommand
00546 
00547         LABEL WIDGET OPTIONS
00548 
00549             text, textvariable, underline, image, compound, width
00550 
00551         WIDGET STATES
00552 
00553             active, disabled, focus, pressed, selected, background,
00554             readonly, alternate, invalid
00555         """
00556         master = setup_master(master)
00557         if not getattr(master, '_tile_loaded', False):
00558             # Load tile now, if needed
00559             _load_tile(master)
00560         tkinter.Widget.__init__(self, master, widgetname, kw=kw)
00561 
00562 
00563     def identify(self, x, y):
00564         """Returns the name of the element at position x, y, or the empty
00565         string if the point does not lie within any element.
00566 
00567         x and y are pixel coordinates relative to the widget."""
00568         return self.tk.call(self._w, "identify", x, y)
00569 
00570 
00571     def instate(self, statespec, callback=None, *args, **kw):
00572         """Test the widget's state.
00573 
00574         If callback is not specified, returns True if the widget state
00575         matches statespec and False otherwise. If callback is specified,
00576         then it will be invoked with *args, **kw if the widget state
00577         matches statespec. statespec is expected to be a sequence."""
00578         ret = self.tk.call(self._w, "instate", ' '.join(statespec))
00579         if ret and callback:
00580             return callback(*args, **kw)
00581 
00582         return bool(ret)
00583 
00584 
00585     def state(self, statespec=None):
00586         """Modify or inquire widget state.
00587 
00588         Widget state is returned if statespec is None, otherwise it is
00589         set according to the statespec flags and then a new state spec
00590         is returned indicating which flags were changed. statespec is
00591         expected to be a sequence."""
00592         if statespec is not None:
00593             statespec = ' '.join(statespec)
00594 
00595         return self.tk.splitlist(str(self.tk.call(self._w, "state", statespec)))
00596 
00597 
00598 class Button(Widget):
00599     """Ttk Button widget, displays a textual label and/or image, and
00600     evaluates a command when pressed."""
00601 
00602     def __init__(self, master=None, **kw):
00603         """Construct a Ttk Button widget with the parent master.
00604 
00605         STANDARD OPTIONS
00606 
00607             class, compound, cursor, image, state, style, takefocus,
00608             text, textvariable, underline, width
00609 
00610         WIDGET-SPECIFIC OPTIONS
00611 
00612             command, default, width
00613         """
00614         Widget.__init__(self, master, "ttk::button", kw)
00615 
00616 
00617     def invoke(self):
00618         """Invokes the command associated with the button."""
00619         return self.tk.call(self._w, "invoke")
00620 
00621 
00622 class Checkbutton(Widget):
00623     """Ttk Checkbutton widget which is either in on- or off-state."""
00624 
00625     def __init__(self, master=None, **kw):
00626         """Construct a Ttk Checkbutton widget with the parent master.
00627 
00628         STANDARD OPTIONS
00629 
00630             class, compound, cursor, image, state, style, takefocus,
00631             text, textvariable, underline, width
00632 
00633         WIDGET-SPECIFIC OPTIONS
00634 
00635             command, offvalue, onvalue, variable
00636         """
00637         Widget.__init__(self, master, "ttk::checkbutton", kw)
00638 
00639 
00640     def invoke(self):
00641         """Toggles between the selected and deselected states and
00642         invokes the associated command. If the widget is currently
00643         selected, sets the option variable to the offvalue option
00644         and deselects the widget; otherwise, sets the option variable
00645         to the option onvalue.
00646 
00647         Returns the result of the associated command."""
00648         return self.tk.call(self._w, "invoke")
00649 
00650 
00651 class Entry(Widget, tkinter.Entry):
00652     """Ttk Entry widget displays a one-line text string and allows that
00653     string to be edited by the user."""
00654 
00655     def __init__(self, master=None, widget=None, **kw):
00656         """Constructs a Ttk Entry widget with the parent master.
00657 
00658         STANDARD OPTIONS
00659 
00660             class, cursor, style, takefocus, xscrollcommand
00661 
00662         WIDGET-SPECIFIC OPTIONS
00663 
00664             exportselection, invalidcommand, justify, show, state,
00665             textvariable, validate, validatecommand, width
00666 
00667         VALIDATION MODES
00668 
00669             none, key, focus, focusin, focusout, all
00670         """
00671         Widget.__init__(self, master, widget or "ttk::entry", kw)
00672 
00673 
00674     def bbox(self, index):
00675         """Return a tuple of (x, y, width, height) which describes the
00676         bounding box of the character given by index."""
00677         return self.tk.call(self._w, "bbox", index)
00678 
00679 
00680     def identify(self, x, y):
00681         """Returns the name of the element at position x, y, or the
00682         empty string if the coordinates are outside the window."""
00683         return self.tk.call(self._w, "identify", x, y)
00684 
00685 
00686     def validate(self):
00687         """Force revalidation, independent of the conditions specified
00688         by the validate option. Returns False if validation fails, True
00689         if it succeeds. Sets or clears the invalid state accordingly."""
00690         return bool(self.tk.call(self._w, "validate"))
00691 
00692 
00693 class Combobox(Entry):
00694     """Ttk Combobox widget combines a text field with a pop-down list of
00695     values."""
00696 
00697     def __init__(self, master=None, **kw):
00698         """Construct a Ttk Combobox widget with the parent master.
00699 
00700         STANDARD OPTIONS
00701 
00702             class, cursor, style, takefocus
00703 
00704         WIDGET-SPECIFIC OPTIONS
00705 
00706             exportselection, justify, height, postcommand, state,
00707             textvariable, values, width
00708         """
00709         # The "values" option may need special formatting, so leave to
00710         # _format_optdict the responsibility to format it
00711         if "values" in kw:
00712             kw["values"] = _format_optdict({'v': kw["values"]})[1]
00713 
00714         Entry.__init__(self, master, "ttk::combobox", **kw)
00715 
00716 
00717     def __setitem__(self, item, value):
00718         if item == "values":
00719             value = _format_optdict({item: value})[1]
00720 
00721         Entry.__setitem__(self, item, value)
00722 
00723 
00724     def configure(self, cnf=None, **kw):
00725         """Custom Combobox configure, created to properly format the values
00726         option."""
00727         if "values" in kw:
00728             kw["values"] = _format_optdict({'v': kw["values"]})[1]
00729 
00730         return Entry.configure(self, cnf, **kw)
00731 
00732 
00733     def current(self, newindex=None):
00734         """If newindex is supplied, sets the combobox value to the
00735         element at position newindex in the list of values. Otherwise,
00736         returns the index of the current value in the list of values
00737         or -1 if the current value does not appear in the list."""
00738         return self.tk.call(self._w, "current", newindex)
00739 
00740 
00741     def set(self, value):
00742         """Sets the value of the combobox to value."""
00743         self.tk.call(self._w, "set", value)
00744 
00745 
00746 class Frame(Widget):
00747     """Ttk Frame widget is a container, used to group other widgets
00748     together."""
00749 
00750     def __init__(self, master=None, **kw):
00751         """Construct a Ttk Frame with parent master.
00752 
00753         STANDARD OPTIONS
00754 
00755             class, cursor, style, takefocus
00756 
00757         WIDGET-SPECIFIC OPTIONS
00758 
00759             borderwidth, relief, padding, width, height
00760         """
00761         Widget.__init__(self, master, "ttk::frame", kw)
00762 
00763 
00764 class Label(Widget):
00765     """Ttk Label widget displays a textual label and/or image."""
00766 
00767     def __init__(self, master=None, **kw):
00768         """Construct a Ttk Label with parent master.
00769 
00770         STANDARD OPTIONS
00771 
00772             class, compound, cursor, image, style, takefocus, text,
00773             textvariable, underline, width
00774 
00775         WIDGET-SPECIFIC OPTIONS
00776 
00777             anchor, background, font, foreground, justify, padding,
00778             relief, text, wraplength
00779         """
00780         Widget.__init__(self, master, "ttk::label", kw)
00781 
00782 
00783 class Labelframe(Widget):
00784     """Ttk Labelframe widget is a container used to group other widgets
00785     together. It has an optional label, which may be a plain text string
00786     or another widget."""
00787 
00788     def __init__(self, master=None, **kw):
00789         """Construct a Ttk Labelframe with parent master.
00790 
00791         STANDARD OPTIONS
00792 
00793             class, cursor, style, takefocus
00794 
00795         WIDGET-SPECIFIC OPTIONS
00796             labelanchor, text, underline, padding, labelwidget, width,
00797             height
00798         """
00799         Widget.__init__(self, master, "ttk::labelframe", kw)
00800 
00801 LabelFrame = Labelframe # tkinter name compatibility
00802 
00803 
00804 class Menubutton(Widget):
00805     """Ttk Menubutton widget displays a textual label and/or image, and
00806     displays a menu when pressed."""
00807 
00808     def __init__(self, master=None, **kw):
00809         """Construct a Ttk Menubutton with parent master.
00810 
00811         STANDARD OPTIONS
00812 
00813             class, compound, cursor, image, state, style, takefocus,
00814             text, textvariable, underline, width
00815 
00816         WIDGET-SPECIFIC OPTIONS
00817 
00818             direction, menu
00819         """
00820         Widget.__init__(self, master, "ttk::menubutton", kw)
00821 
00822 
00823 class Notebook(Widget):
00824     """Ttk Notebook widget manages a collection of windows and displays
00825     a single one at a time. Each child window is associated with a tab,
00826     which the user may select to change the currently-displayed window."""
00827 
00828     def __init__(self, master=None, **kw):
00829         """Construct a Ttk Notebook with parent master.
00830 
00831         STANDARD OPTIONS
00832 
00833             class, cursor, style, takefocus
00834 
00835         WIDGET-SPECIFIC OPTIONS
00836 
00837             height, padding, width
00838 
00839         TAB OPTIONS
00840 
00841             state, sticky, padding, text, image, compound, underline
00842 
00843         TAB IDENTIFIERS (tab_id)
00844 
00845             The tab_id argument found in several methods may take any of
00846             the following forms:
00847 
00848                 * An integer between zero and the number of tabs
00849                 * The name of a child window
00850                 * A positional specification of the form "@x,y", which
00851                   defines the tab
00852                 * The string "current", which identifies the
00853                   currently-selected tab
00854                 * The string "end", which returns the number of tabs (only
00855                   valid for method index)
00856         """
00857         Widget.__init__(self, master, "ttk::notebook", kw)
00858 
00859 
00860     def add(self, child, **kw):
00861         """Adds a new tab to the notebook.
00862 
00863         If window is currently managed by the notebook but hidden, it is
00864         restored to its previous position."""
00865         self.tk.call(self._w, "add", child, *(_format_optdict(kw)))
00866 
00867 
00868     def forget(self, tab_id):
00869         """Removes the tab specified by tab_id, unmaps and unmanages the
00870         associated window."""
00871         self.tk.call(self._w, "forget", tab_id)
00872 
00873 
00874     def hide(self, tab_id):
00875         """Hides the tab specified by tab_id.
00876 
00877         The tab will not be displayed, but the associated window remains
00878         managed by the notebook and its configuration remembered. Hidden
00879         tabs may be restored with the add command."""
00880         self.tk.call(self._w, "hide", tab_id)
00881 
00882 
00883     def identify(self, x, y):
00884         """Returns the name of the tab element at position x, y, or the
00885         empty string if none."""
00886         return self.tk.call(self._w, "identify", x, y)
00887 
00888 
00889     def index(self, tab_id):
00890         """Returns the numeric index of the tab specified by tab_id, or
00891         the total number of tabs if tab_id is the string "end"."""
00892         return self.tk.call(self._w, "index", tab_id)
00893 
00894 
00895     def insert(self, pos, child, **kw):
00896         """Inserts a pane at the specified position.
00897 
00898         pos is either the string end, an integer index, or the name of
00899         a managed child. If child is already managed by the notebook,
00900         moves it to the specified position."""
00901         self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
00902 
00903 
00904     def select(self, tab_id=None):
00905         """Selects the specified tab.
00906 
00907         The associated child window will be displayed, and the
00908         previously-selected window (if different) is unmapped. If tab_id
00909         is omitted, returns the widget name of the currently selected
00910         pane."""
00911         return self.tk.call(self._w, "select", tab_id)
00912 
00913 
00914     def tab(self, tab_id, option=None, **kw):
00915         """Query or modify the options of the specific tab_id.
00916 
00917         If kw is not given, returns a dict of the tab option values. If option
00918         is specified, returns the value of that option. Otherwise, sets the
00919         options to the corresponding values."""
00920         if option is not None:
00921             kw[option] = None
00922         return _val_or_dict(kw, self.tk.call, self._w, "tab", tab_id)
00923 
00924 
00925     def tabs(self):
00926         """Returns a list of windows managed by the notebook."""
00927         return self.tk.call(self._w, "tabs") or ()
00928 
00929 
00930     def enable_traversal(self):
00931         """Enable keyboard traversal for a toplevel window containing
00932         this notebook.
00933 
00934         This will extend the bindings for the toplevel window containing
00935         this notebook as follows:
00936 
00937             Control-Tab: selects the tab following the currently selected
00938                          one
00939 
00940             Shift-Control-Tab: selects the tab preceding the currently
00941                                selected one
00942 
00943             Alt-K: where K is the mnemonic (underlined) character of any
00944                    tab, will select that tab.
00945 
00946         Multiple notebooks in a single toplevel may be enabled for
00947         traversal, including nested notebooks. However, notebook traversal
00948         only works properly if all panes are direct children of the
00949         notebook."""
00950         # The only, and good, difference I see is about mnemonics, which works
00951         # after calling this method. Control-Tab and Shift-Control-Tab always
00952         # works (here at least).
00953         self.tk.call("ttk::notebook::enableTraversal", self._w)
00954 
00955 
00956 class Panedwindow(Widget, tkinter.PanedWindow):
00957     """Ttk Panedwindow widget displays a number of subwindows, stacked
00958     either vertically or horizontally."""
00959 
00960     def __init__(self, master=None, **kw):
00961         """Construct a Ttk Panedwindow with parent master.
00962 
00963         STANDARD OPTIONS
00964 
00965             class, cursor, style, takefocus
00966 
00967         WIDGET-SPECIFIC OPTIONS
00968 
00969             orient, width, height
00970 
00971         PANE OPTIONS
00972 
00973             weight
00974         """
00975         Widget.__init__(self, master, "ttk::panedwindow", kw)
00976 
00977 
00978     forget = tkinter.PanedWindow.forget # overrides Pack.forget
00979 
00980 
00981     def insert(self, pos, child, **kw):
00982         """Inserts a pane at the specified positions.
00983 
00984         pos is either the string end, and integer index, or the name
00985         of a child. If child is already managed by the paned window,
00986         moves it to the specified position."""
00987         self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
00988 
00989 
00990     def pane(self, pane, option=None, **kw):
00991         """Query or modify the options of the specified pane.
00992 
00993         pane is either an integer index or the name of a managed subwindow.
00994         If kw is not given, returns a dict of the pane option values. If
00995         option is specified then the value for that option is returned.
00996         Otherwise, sets the options to the corresponding values."""
00997         if option is not None:
00998             kw[option] = None
00999         return _val_or_dict(kw, self.tk.call, self._w, "pane", pane)
01000 
01001 
01002     def sashpos(self, index, newpos=None):
01003         """If newpos is specified, sets the position of sash number index.
01004 
01005         May adjust the positions of adjacent sashes to ensure that
01006         positions are monotonically increasing. Sash positions are further
01007         constrained to be between 0 and the total size of the widget.
01008 
01009         Returns the new position of sash number index."""
01010         return self.tk.call(self._w, "sashpos", index, newpos)
01011 
01012 PanedWindow = Panedwindow # tkinter name compatibility
01013 
01014 
01015 class Progressbar(Widget):
01016     """Ttk Progressbar widget shows the status of a long-running
01017     operation. They can operate in two modes: determinate mode shows the
01018     amount completed relative to the total amount of work to be done, and
01019     indeterminate mode provides an animated display to let the user know
01020     that something is happening."""
01021 
01022     def __init__(self, master=None, **kw):
01023         """Construct a Ttk Progressbar with parent master.
01024 
01025         STANDARD OPTIONS
01026 
01027             class, cursor, style, takefocus
01028 
01029         WIDGET-SPECIFIC OPTIONS
01030 
01031             orient, length, mode, maximum, value, variable, phase
01032         """
01033         Widget.__init__(self, master, "ttk::progressbar", kw)
01034 
01035 
01036     def start(self, interval=None):
01037         """Begin autoincrement mode: schedules a recurring timer event
01038         that calls method step every interval milliseconds.
01039 
01040         interval defaults to 50 milliseconds (20 steps/second) if ommited."""
01041         self.tk.call(self._w, "start", interval)
01042 
01043 
01044     def step(self, amount=None):
01045         """Increments the value option by amount.
01046 
01047         amount defaults to 1.0 if omitted."""
01048         self.tk.call(self._w, "step", amount)
01049 
01050 
01051     def stop(self):
01052         """Stop autoincrement mode: cancels any recurring timer event
01053         initiated by start."""
01054         self.tk.call(self._w, "stop")
01055 
01056 
01057 class Radiobutton(Widget):
01058     """Ttk Radiobutton widgets are used in groups to show or change a
01059     set of mutually-exclusive options."""
01060 
01061     def __init__(self, master=None, **kw):
01062         """Construct a Ttk Radiobutton with parent master.
01063 
01064         STANDARD OPTIONS
01065 
01066             class, compound, cursor, image, state, style, takefocus,
01067             text, textvariable, underline, width
01068 
01069         WIDGET-SPECIFIC OPTIONS
01070 
01071             command, value, variable
01072         """
01073         Widget.__init__(self, master, "ttk::radiobutton", kw)
01074 
01075 
01076     def invoke(self):
01077         """Sets the option variable to the option value, selects the
01078         widget, and invokes the associated command.
01079 
01080         Returns the result of the command, or an empty string if
01081         no command is specified."""
01082         return self.tk.call(self._w, "invoke")
01083 
01084 
01085 class Scale(Widget, tkinter.Scale):
01086     """Ttk Scale widget is typically used to control the numeric value of
01087     a linked variable that varies uniformly over some range."""
01088 
01089     def __init__(self, master=None, **kw):
01090         """Construct a Ttk Scale with parent master.
01091 
01092         STANDARD OPTIONS
01093 
01094             class, cursor, style, takefocus
01095 
01096         WIDGET-SPECIFIC OPTIONS
01097 
01098             command, from, length, orient, to, value, variable
01099         """
01100         Widget.__init__(self, master, "ttk::scale", kw)
01101 
01102 
01103     def configure(self, cnf=None, **kw):
01104         """Modify or query scale options.
01105 
01106         Setting a value for any of the "from", "from_" or "to" options
01107         generates a <<RangeChanged>> event."""
01108         if cnf:
01109             kw.update(cnf)
01110         Widget.configure(self, **kw)
01111         if any(['from' in kw, 'from_' in kw, 'to' in kw]):
01112             self.event_generate('<<RangeChanged>>')
01113 
01114 
01115     def get(self, x=None, y=None):
01116         """Get the current value of the value option, or the value
01117         corresponding to the coordinates x, y if they are specified.
01118 
01119         x and y are pixel coordinates relative to the scale widget
01120         origin."""
01121         return self.tk.call(self._w, 'get', x, y)
01122 
01123 
01124 class Scrollbar(Widget, tkinter.Scrollbar):
01125     """Ttk Scrollbar controls the viewport of a scrollable widget."""
01126 
01127     def __init__(self, master=None, **kw):
01128         """Construct a Ttk Scrollbar with parent master.
01129 
01130         STANDARD OPTIONS
01131 
01132             class, cursor, style, takefocus
01133 
01134         WIDGET-SPECIFIC OPTIONS
01135 
01136             command, orient
01137         """
01138         Widget.__init__(self, master, "ttk::scrollbar", kw)
01139 
01140 
01141 class Separator(Widget):
01142     """Ttk Separator widget displays a horizontal or vertical separator
01143     bar."""
01144 
01145     def __init__(self, master=None, **kw):
01146         """Construct a Ttk Separator with parent master.
01147 
01148         STANDARD OPTIONS
01149 
01150             class, cursor, style, takefocus
01151 
01152         WIDGET-SPECIFIC OPTIONS
01153 
01154             orient
01155         """
01156         Widget.__init__(self, master, "ttk::separator", kw)
01157 
01158 
01159 class Sizegrip(Widget):
01160     """Ttk Sizegrip allows the user to resize the containing toplevel
01161     window by pressing and dragging the grip."""
01162 
01163     def __init__(self, master=None, **kw):
01164         """Construct a Ttk Sizegrip with parent master.
01165 
01166         STANDARD OPTIONS
01167 
01168             class, cursor, state, style, takefocus
01169         """
01170         Widget.__init__(self, master, "ttk::sizegrip", kw)
01171 
01172 
01173 class Treeview(Widget, tkinter.XView, tkinter.YView):
01174     """Ttk Treeview widget displays a hierarchical collection of items.
01175 
01176     Each item has a textual label, an optional image, and an optional list
01177     of data values. The data values are displayed in successive columns
01178     after the tree label."""
01179 
01180     def __init__(self, master=None, **kw):
01181         """Construct a Ttk Treeview with parent master.
01182 
01183         STANDARD OPTIONS
01184 
01185             class, cursor, style, takefocus, xscrollcommand,
01186             yscrollcommand
01187 
01188         WIDGET-SPECIFIC OPTIONS
01189 
01190             columns, displaycolumns, height, padding, selectmode, show
01191 
01192         ITEM OPTIONS
01193 
01194             text, image, values, open, tags
01195 
01196         TAG OPTIONS
01197 
01198             foreground, background, font, image
01199         """
01200         Widget.__init__(self, master, "ttk::treeview", kw)
01201 
01202 
01203     def bbox(self, item, column=None):
01204         """Returns the bounding box (relative to the treeview widget's
01205         window) of the specified item in the form x y width height.
01206 
01207         If column is specified, returns the bounding box of that cell.
01208         If the item is not visible (i.e., if it is a descendant of a
01209         closed item or is scrolled offscreen), returns an empty string."""
01210         return self.tk.call(self._w, "bbox", item, column)
01211 
01212 
01213     def get_children(self, item=None):
01214         """Returns a tuple of children belonging to item.
01215 
01216         If item is not specified, returns root children."""
01217         return self.tk.call(self._w, "children", item or '') or ()
01218 
01219 
01220     def set_children(self, item, *newchildren):
01221         """Replaces item's child with newchildren.
01222 
01223         Children present in item that are not present in newchildren
01224         are detached from tree. No items in newchildren may be an
01225         ancestor of item."""
01226         self.tk.call(self._w, "children", item, newchildren)
01227 
01228 
01229     def column(self, column, option=None, **kw):
01230         """Query or modify the options for the specified column.
01231 
01232         If kw is not given, returns a dict of the column option values. If
01233         option is specified then the value for that option is returned.
01234         Otherwise, sets the options to the corresponding values."""
01235         if option is not None:
01236             kw[option] = None
01237         return _val_or_dict(kw, self.tk.call, self._w, "column", column)
01238 
01239 
01240     def delete(self, *items):
01241         """Delete all specified items and all their descendants. The root
01242         item may not be deleted."""
01243         self.tk.call(self._w, "delete", items)
01244 
01245 
01246     def detach(self, *items):
01247         """Unlinks all of the specified items from the tree.
01248 
01249         The items and all of their descendants are still present, and may
01250         be reinserted at another point in the tree, but will not be
01251         displayed. The root item may not be detached."""
01252         self.tk.call(self._w, "detach", items)
01253 
01254 
01255     def exists(self, item):
01256         """Returns True if the specified item is present in the three,
01257         False otherwise."""
01258         return bool(self.tk.call(self._w, "exists", item))
01259 
01260 
01261     def focus(self, item=None):
01262         """If item is specified, sets the focus item to item. Otherwise,
01263         returns the current focus item, or '' if there is none."""
01264         return self.tk.call(self._w, "focus", item)
01265 
01266 
01267     def heading(self, column, option=None, **kw):
01268         """Query or modify the heading options for the specified column.
01269 
01270         If kw is not given, returns a dict of the heading option values. If
01271         option is specified then the value for that option is returned.
01272         Otherwise, sets the options to the corresponding values.
01273 
01274         Valid options/values are:
01275             text: text
01276                 The text to display in the column heading
01277             image: image_name
01278                 Specifies an image to display to the right of the column
01279                 heading
01280             anchor: anchor
01281                 Specifies how the heading text should be aligned. One of
01282                 the standard Tk anchor values
01283             command: callback
01284                 A callback to be invoked when the heading label is
01285                 pressed.
01286 
01287         To configure the tree column heading, call this with column = "#0" """
01288         cmd = kw.get('command')
01289         if cmd and not isinstance(cmd, str):
01290             # callback not registered yet, do it now
01291             kw['command'] = self.master.register(cmd, self._substitute)
01292 
01293         if option is not None:
01294             kw[option] = None
01295 
01296         return _val_or_dict(kw, self.tk.call, self._w, 'heading', column)
01297 
01298 
01299     def identify(self, component, x, y):
01300         """Returns a description of the specified component under the
01301         point given by x and y, or the empty string if no such component
01302         is present at that position."""
01303         return self.tk.call(self._w, "identify", component, x, y)
01304 
01305 
01306     def identify_row(self, y):
01307         """Returns the item ID of the item at position y."""
01308         return self.identify("row", 0, y)
01309 
01310 
01311     def identify_column(self, x):
01312         """Returns the data column identifier of the cell at position x.
01313 
01314         The tree column has ID #0."""
01315         return self.identify("column", x, 0)
01316 
01317 
01318     def identify_region(self, x, y):
01319         """Returns one of:
01320 
01321         heading: Tree heading area.
01322         separator: Space between two columns headings;
01323         tree: The tree area.
01324         cell: A data cell.
01325 
01326         * Availability: Tk 8.6"""
01327         return self.identify("region", x, y)
01328 
01329 
01330     def identify_element(self, x, y):
01331         """Returns the element at position x, y.
01332 
01333         * Availability: Tk 8.6"""
01334         return self.identify("element", x, y)
01335 
01336 
01337     def index(self, item):
01338         """Returns the integer index of item within its parent's list
01339         of children."""
01340         return self.tk.call(self._w, "index", item)
01341 
01342 
01343     def insert(self, parent, index, iid=None, **kw):
01344         """Creates a new item and return the item identifier of the newly
01345         created item.
01346 
01347         parent is the item ID of the parent item, or the empty string
01348         to create a new top-level item. index is an integer, or the value
01349         end, specifying where in the list of parent's children to insert
01350         the new item. If index is less than or equal to zero, the new node
01351         is inserted at the beginning, if index is greater than or equal to
01352         the current number of children, it is inserted at the end. If iid
01353         is specified, it is used as the item identifier, iid must not
01354         already exist in the tree. Otherwise, a new unique identifier
01355         is generated."""
01356         opts = _format_optdict(kw)
01357         if iid:
01358             res = self.tk.call(self._w, "insert", parent, index,
01359                 "-id", iid, *opts)
01360         else:
01361             res = self.tk.call(self._w, "insert", parent, index, *opts)
01362 
01363         return res
01364 
01365 
01366     def item(self, item, option=None, **kw):
01367         """Query or modify the options for the specified item.
01368 
01369         If no options are given, a dict with options/values for the item
01370         is returned. If option is specified then the value for that option
01371         is returned. Otherwise, sets the options to the corresponding
01372         values as given by kw."""
01373         if option is not None:
01374             kw[option] = None
01375         return _val_or_dict(kw, self.tk.call, self._w, "item", item)
01376 
01377 
01378     def move(self, item, parent, index):
01379         """Moves item to position index in parent's list of children.
01380 
01381         It is illegal to move an item under one of its descendants. If
01382         index is less than or equal to zero, item is moved to the
01383         beginning, if greater than or equal to the number of children,
01384         it is moved to the end. If item was detached it is reattached."""
01385         self.tk.call(self._w, "move", item, parent, index)
01386 
01387     reattach = move # A sensible method name for reattaching detached items
01388 
01389 
01390     def next(self, item):
01391         """Returns the identifier of item's next sibling, or '' if item
01392         is the last child of its parent."""
01393         return self.tk.call(self._w, "next", item)
01394 
01395 
01396     def parent(self, item):
01397         """Returns the ID of the parent of item, or '' if item is at the
01398         top level of the hierarchy."""
01399         return self.tk.call(self._w, "parent", item)
01400 
01401 
01402     def prev(self, item):
01403         """Returns the identifier of item's previous sibling, or '' if
01404         item is the first child of its parent."""
01405         return self.tk.call(self._w, "prev", item)
01406 
01407 
01408     def see(self, item):
01409         """Ensure that item is visible.
01410 
01411         Sets all of item's ancestors open option to True, and scrolls
01412         the widget if necessary so that item is within the visible
01413         portion of the tree."""
01414         self.tk.call(self._w, "see", item)
01415 
01416 
01417     def selection(self, selop=None, items=None):
01418         """If selop is not specified, returns selected items."""
01419         return self.tk.call(self._w, "selection", selop, items)
01420 
01421 
01422     def selection_set(self, items):
01423         """items becomes the new selection."""
01424         self.selection("set", items)
01425 
01426 
01427     def selection_add(self, items):
01428         """Add items to the selection."""
01429         self.selection("add", items)
01430 
01431 
01432     def selection_remove(self, items):
01433         """Remove items from the selection."""
01434         self.selection("remove", items)
01435 
01436 
01437     def selection_toggle(self, items):
01438         """Toggle the selection state of each item in items."""
01439         self.selection("toggle", items)
01440 
01441 
01442     def set(self, item, column=None, value=None):
01443         """With one argument, returns a dictionary of column/value pairs
01444         for the specified item. With two arguments, returns the current
01445         value of the specified column. With three arguments, sets the
01446         value of given column in given item to the specified value."""
01447         res = self.tk.call(self._w, "set", item, column, value)
01448         if column is None and value is None:
01449             return _dict_from_tcltuple(res, False)
01450         else:
01451             return res
01452 
01453 
01454     def tag_bind(self, tagname, sequence=None, callback=None):
01455         """Bind a callback for the given event sequence to the tag tagname.
01456         When an event is delivered to an item, the callbacks for each
01457         of the item's tags option are called."""
01458         self._bind((self._w, "tag", "bind", tagname), sequence, callback, add=0)
01459 
01460 
01461     def tag_configure(self, tagname, option=None, **kw):
01462         """Query or modify the options for the specified tagname.
01463 
01464         If kw is not given, returns a dict of the option settings for tagname.
01465         If option is specified, returns the value for that option for the
01466         specified tagname. Otherwise, sets the options to the corresponding
01467         values for the given tagname."""
01468         if option is not None:
01469             kw[option] = None
01470         return _val_or_dict(kw, self.tk.call, self._w, "tag", "configure",
01471             tagname)
01472 
01473 
01474     def tag_has(self, tagname, item=None):
01475         """If item is specified, returns 1 or 0 depending on whether the
01476         specified item has the given tagname. Otherwise, returns a list of
01477         all items which have the specified tag.
01478 
01479         * Availability: Tk 8.6"""
01480         return self.tk.call(self._w, "tag", "has", tagname, item)
01481 
01482 
01483 # Extensions
01484 
01485 class LabeledScale(Frame):
01486     """A Ttk Scale widget with a Ttk Label widget indicating its
01487     current value.
01488 
01489     The Ttk Scale can be accessed through instance.scale, and Ttk Label
01490     can be accessed through instance.label"""
01491 
01492     def __init__(self, master=None, variable=None, from_=0, to=10, **kw):
01493         """Construct an horizontal LabeledScale with parent master, a
01494         variable to be associated with the Ttk Scale widget and its range.
01495         If variable is not specified, a tkinter.IntVar is created.
01496 
01497         WIDGET-SPECIFIC OPTIONS
01498 
01499             compound: 'top' or 'bottom'
01500                 Specifies how to display the label relative to the scale.
01501                 Defaults to 'top'.
01502         """
01503         self._label_top = kw.pop('compound', 'top') == 'top'
01504 
01505         Frame.__init__(self, master, **kw)
01506         self._variable = variable or tkinter.IntVar(master)
01507         self._variable.set(from_)
01508         self._last_valid = from_
01509 
01510         self.label = Label(self)
01511         self.scale = Scale(self, variable=self._variable, from_=from_, to=to)
01512         self.scale.bind('<<RangeChanged>>', self._adjust)
01513 
01514         # position scale and label according to the compound option
01515         scale_side = 'bottom' if self._label_top else 'top'
01516         label_side = 'top' if scale_side == 'bottom' else 'bottom'
01517         self.scale.pack(side=scale_side, fill='x')
01518         tmp = Label(self).pack(side=label_side) # place holder
01519         self.label.place(anchor='n' if label_side == 'top' else 's')
01520 
01521         # update the label as scale or variable changes
01522         self.__tracecb = self._variable.trace_variable('w', self._adjust)
01523         self.bind('<Configure>', self._adjust)
01524         self.bind('<Map>', self._adjust)
01525 
01526 
01527     def destroy(self):
01528         """Destroy this widget and possibly its associated variable."""
01529         try:
01530             self._variable.trace_vdelete('w', self.__tracecb)
01531         except AttributeError:
01532             # widget has been destroyed already
01533             pass
01534         else:
01535             del self._variable
01536             Frame.destroy(self)
01537 
01538 
01539     def _adjust(self, *args):
01540         """Adjust the label position according to the scale."""
01541         def adjust_label():
01542             self.update_idletasks() # "force" scale redraw
01543 
01544             x, y = self.scale.coords()
01545             if self._label_top:
01546                 y = self.scale.winfo_y() - self.label.winfo_reqheight()
01547             else:
01548                 y = self.scale.winfo_reqheight() + self.label.winfo_reqheight()
01549 
01550             self.label.place_configure(x=x, y=y)
01551 
01552         from_, to = self.scale['from'], self.scale['to']
01553         if to < from_:
01554             from_, to = to, from_
01555         newval = self._variable.get()
01556         if not from_ <= newval <= to:
01557             # value outside range, set value back to the last valid one
01558             self.value = self._last_valid
01559             return
01560 
01561         self._last_valid = newval
01562         self.label['text'] = newval
01563         self.after_idle(adjust_label)
01564 
01565 
01566     def _get_value(self):
01567         """Return current scale value."""
01568         return self._variable.get()
01569 
01570 
01571     def _set_value(self, val):
01572         """Set new scale value."""
01573         self._variable.set(val)
01574 
01575 
01576     value = property(_get_value, _set_value)
01577 
01578 
01579 class OptionMenu(Menubutton):
01580     """Themed OptionMenu, based after tkinter's OptionMenu, which allows
01581     the user to select a value from a menu."""
01582 
01583     def __init__(self, master, variable, default=None, *values, **kwargs):
01584         """Construct a themed OptionMenu widget with master as the parent,
01585         the resource textvariable set to variable, the initially selected
01586         value specified by the default parameter, the menu values given by
01587         *values and additional keywords.
01588 
01589         WIDGET-SPECIFIC OPTIONS
01590 
01591             style: stylename
01592                 Menubutton style.
01593             direction: 'above', 'below', 'left', 'right', or 'flush'
01594                 Menubutton direction.
01595             command: callback
01596                 A callback that will be invoked after selecting an item.
01597         """
01598         kw = {'textvariable': variable, 'style': kwargs.pop('style', None),
01599               'direction': kwargs.pop('direction', None)}
01600         Menubutton.__init__(self, master, **kw)
01601         self['menu'] = tkinter.Menu(self, tearoff=False)
01602 
01603         self._variable = variable
01604         self._callback = kwargs.pop('command', None)
01605         if kwargs:
01606             raise tkinter.TclError('unknown option -%s' % (
01607                 next(iter(kwargs.keys()))))
01608 
01609         self.set_menu(default, *values)
01610 
01611 
01612     def __getitem__(self, item):
01613         if item == 'menu':
01614             return self.nametowidget(Menubutton.__getitem__(self, item))
01615 
01616         return Menubutton.__getitem__(self, item)
01617 
01618 
01619     def set_menu(self, default=None, *values):
01620         """Build a new menu of radiobuttons with *values and optionally
01621         a default value."""
01622         menu = self['menu']
01623         menu.delete(0, 'end')
01624         for val in values:
01625             menu.add_radiobutton(label=val,
01626                 command=tkinter._setit(self._variable, val, self._callback))
01627 
01628         if default:
01629             self._variable.set(default)
01630 
01631 
01632     def destroy(self):
01633         """Destroy this widget and its associated variable."""
01634         del self._variable
01635         Menubutton.destroy(self)