codekingpro/portable-devtools
114k
1"""Ttk wrapper.2 3This module provides classes to allow using Tk themed widget set.4 5Ttk is based on a revised and enhanced version of6TIP #48 (http://tip.tcl.tk/48) specified style engine.7 8Its basic idea is to separate, to the extent possible, the code9implementing a widget's behavior from the code implementing its10appearance. Widget class bindings are primarily responsible for11maintaining the widget state and invoking callbacks, all aspects12of the widgets appearance lies at Themes.13"""14 15__version__ = "0.3.1"16 17__author__ = "Guilherme Polo <ggpolo@gmail.com>"18 19__all__ = ["Button", "Checkbutton", "Combobox", "Entry", "Frame", "Label",20 "Labelframe", "LabelFrame", "Menubutton", "Notebook", "Panedwindow",21 "PanedWindow", "Progressbar", "Radiobutton", "Scale", "Scrollbar",22 "Separator", "Sizegrip", "Spinbox", "Style", "Treeview",23 # Extensions24 "LabeledScale", "OptionMenu",25 # functions26 "tclobjs_to_py", "setup_master"]27 28import tkinter29from tkinter import _flatten, _join, _stringify, _splitdict30 31 32def _format_optvalue(value, script=False):33 """Internal function."""34 if script:35 # if caller passes a Tcl script to tk.call, all the values need to36 # be grouped into words (arguments to a command in Tcl dialect)37 value = _stringify(value)38 elif isinstance(value, (list, tuple)):39 value = _join(value)40 return value41 42def _format_optdict(optdict, script=False, ignore=None):43 """Formats optdict to a tuple to pass it to tk.call.44 45 E.g. (script=False):46 {'foreground': 'blue', 'padding': [1, 2, 3, 4]} returns:47 ('-foreground', 'blue', '-padding', '1 2 3 4')"""48 49 opts = []50 for opt, value in optdict.items():51 if not ignore or opt not in ignore:52 opts.append("-%s" % opt)53 if value is not None:54 opts.append(_format_optvalue(value, script))55 56 return _flatten(opts)57 58def _mapdict_values(items):59 # each value in mapdict is expected to be a sequence, where each item60 # is another sequence containing a state (or several) and a value61 # E.g. (script=False):62 # [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]63 # returns:64 # ['active selected', 'grey', 'focus', [1, 2, 3, 4]]65 opt_val = []66 for *state, val in items:67 if len(state) == 1:68 # if it is empty (something that evaluates to False), then69 # format it to Tcl code to denote the "normal" state70 state = state[0] or ''71 else:72 # group multiple states73 state = ' '.join(state) # raise TypeError if not str74 opt_val.append(state)75 if val is not None:76 opt_val.append(val)77 return opt_val78 79def _format_mapdict(mapdict, script=False):80 """Formats mapdict to pass it to tk.call.81 82 E.g. (script=False):83 {'expand': [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]}84 85 returns:86 87 ('-expand', '{active selected} grey focus {1, 2, 3, 4}')"""88 89 opts = []90 for opt, value in mapdict.items():91 opts.extend(("-%s" % opt,92 _format_optvalue(_mapdict_values(value), script)))93 94 return _flatten(opts)95 96def _format_elemcreate(etype, script=False, *args, **kw):97 """Formats args and kw according to the given element factory etype."""98 specs = ()99 opts = ()100 if etype == "image": # define an element based on an image101 # first arg should be the default image name102 iname = args[0]103 # next args, if any, are statespec/value pairs which is almost104 # a mapdict, but we just need the value105 imagespec = (iname, *_mapdict_values(args[1:]))106 if script:107 specs = (imagespec,)108 else:109 specs = (_join(imagespec),)110 opts = _format_optdict(kw, script)111 112 if etype == "vsapi":113 # define an element whose visual appearance is drawn using the114 # Microsoft Visual Styles API which is responsible for the115 # themed styles on Windows XP and Vista.116 # Availability: Tk 8.6, Windows XP and Vista.117 if len(args) < 3:118 class_name, part_id = args119 statemap = (((), 1),)120 else:121 class_name, part_id, statemap = args122 specs = (class_name, part_id, tuple(_mapdict_values(statemap)))123 opts = _format_optdict(kw, script)124 125 elif etype == "from": # clone an element126 # it expects a themename and optionally an element to clone from,127 # otherwise it will clone {} (empty element)128 specs = (args[0],) # theme name129 if len(args) > 1: # elementfrom specified130 opts = (_format_optvalue(args[1], script),)131 132 if script:133 specs = _join(specs)134 opts = ' '.join(opts)135 return specs, opts136 else:137 return *specs, opts138 139 140def _format_layoutlist(layout, indent=0, indent_size=2):141 """Formats a layout list so we can pass the result to ttk::style142 layout and ttk::style settings. Note that the layout doesn't have to143 be a list necessarily.144 145 E.g.:146 [("Menubutton.background", None),147 ("Menubutton.button", {"children":148 [("Menubutton.focus", {"children":149 [("Menubutton.padding", {"children":150 [("Menubutton.label", {"side": "left", "expand": 1})]151 })]152 })]153 }),154 ("Menubutton.indicator", {"side": "right"})155 ]156 157 returns:158 159 Menubutton.background160 Menubutton.button -children {161 Menubutton.focus -children {162 Menubutton.padding -children {163 Menubutton.label -side left -expand 1164 }165 }166 }167 Menubutton.indicator -side right"""168 script = []169 170 for layout_elem in layout:171 elem, opts = layout_elem172 opts = opts or {}173 fopts = ' '.join(_format_optdict(opts, True, ("children",)))174 head = "%s%s%s" % (' ' * indent, elem, (" %s" % fopts) if fopts else '')175 176 if "children" in opts:177 script.append(head + " -children {")178 indent += indent_size179 newscript, indent = _format_layoutlist(opts['children'], indent,180 indent_size)181 script.append(newscript)182 indent -= indent_size183 script.append('%s}' % (' ' * indent))184 else:185 script.append(head)186 187 return '\n'.join(script), indent188 189def _script_from_settings(settings):190 """Returns an appropriate script, based on settings, according to191 theme_settings definition to be used by theme_settings and192 theme_create."""193 script = []194 # a script will be generated according to settings passed, which195 # will then be evaluated by Tcl196 for name, opts in settings.items():197 # will format specific keys according to Tcl code198 if opts.get('configure'): # format 'configure'199 s = ' '.join(_format_optdict(opts['configure'], True))200 script.append("ttk::style configure %s %s;" % (name, s))201 202 if opts.get('map'): # format 'map'203 s = ' '.join(_format_mapdict(opts['map'], True))204 script.append("ttk::style map %s %s;" % (name, s))205 206 if 'layout' in opts: # format 'layout' which may be empty207 if not opts['layout']:208 s = 'null' # could be any other word, but this one makes sense209 else:210 s, _ = _format_layoutlist(opts['layout'])211 script.append("ttk::style layout %s {\n%s\n}" % (name, s))212 213 if opts.get('element create'): # format 'element create'214 eopts = opts['element create']215 etype = eopts[0]216 217 # find where args end, and where kwargs start218 argc = 1 # etype was the first one219 while argc < len(eopts) and not hasattr(eopts[argc], 'items'):220 argc += 1221 222 elemargs = eopts[1:argc]223 elemkw = eopts[argc] if argc < len(eopts) and eopts[argc] else {}224 specs, eopts = _format_elemcreate(etype, True, *elemargs, **elemkw)225 226 script.append("ttk::style element create %s %s %s %s" % (227 name, etype, specs, eopts))228 229 return '\n'.join(script)230 231def _list_from_statespec(stuple):232 """Construct a list from the given statespec tuple according to the233 accepted statespec accepted by _format_mapdict."""234 if isinstance(stuple, str):235 return stuple236 result = []237 it = iter(stuple)238 for state, val in zip(it, it):239 if hasattr(state, 'typename'): # this is a Tcl object240 state = str(state).split()241 elif isinstance(state, str):242 state = state.split()243 elif not isinstance(state, (tuple, list)):244 state = (state,)245 if hasattr(val, 'typename'):246 val = str(val)247 result.append((*state, val))248 249 return result250 251def _list_from_layouttuple(tk, ltuple):252 """Construct a list from the tuple returned by ttk::layout, this is253 somewhat the reverse of _format_layoutlist."""254 ltuple = tk.splitlist(ltuple)255 res = []256 257 indx = 0258 while indx < len(ltuple):259 name = ltuple[indx]260 opts = {}261 res.append((name, opts))262 indx += 1263 264 while indx < len(ltuple): # grab name's options265 opt, val = ltuple[indx:indx + 2]266 if not opt.startswith('-'): # found next name267 break268 269 opt = opt[1:] # remove the '-' from the option270 indx += 2271 272 if opt == 'children':273 val = _list_from_layouttuple(tk, val)274 275 opts[opt] = val276 277 return res278 279def _val_or_dict(tk, options, *args):280 """Format options then call Tk command with args and options and return281 the appropriate result.282 283 If no option is specified, a dict is returned. If an option is284 specified with the None value, the value for that option is returned.285 Otherwise, the function just sets the passed options and the caller286 shouldn't be expecting a return value anyway."""287 options = _format_optdict(options)288 res = tk.call(*(args + options))289 290 if len(options) % 2: # option specified without a value, return its value291 return res292 293 return _splitdict(tk, res, conv=_tclobj_to_py)294 295def _convert_stringval(value):296 """Converts a value to, hopefully, a more appropriate Python object."""297 value = str(value)298 try:299 value = int(value)300 except (ValueError, TypeError):301 pass302 303 return value304 305def _to_number(x):306 if isinstance(x, str):307 if '.' in x:308 x = float(x)309 else:310 x = int(x)311 return x312 313def _tclobj_to_py(val):314 """Return value converted from Tcl object to Python object."""315 if val and hasattr(val, '__len__') and not isinstance(val, str):316 if getattr(val[0], 'typename', None) == 'StateSpec':317 val = _list_from_statespec(val)318 else:319 val = list(map(_convert_stringval, val))320 321 elif hasattr(val, 'typename'): # some other (single) Tcl object322 val = _convert_stringval(val)323 324 if isinstance(val, tuple) and len(val) == 0:325 return ''326 return val327 328def tclobjs_to_py(adict):329 """Returns adict with its values converted from Tcl objects to Python330 objects."""331 for opt, val in adict.items():332 adict[opt] = _tclobj_to_py(val)333 334 return adict335 336def setup_master(master=None):337 """If master is not None, itself is returned. If master is None,338 the default master is returned if there is one, otherwise a new339 master is created and returned.340 341 If it is not allowed to use the default root and master is None,342 RuntimeError is raised."""343 if master is None:344 master = tkinter._get_default_root()345 return master346 347 348class Style(object):349 """Manipulate style database."""350 351 _name = "ttk::style"352 353 def __init__(self, master=None):354 master = setup_master(master)355 self.master = master356 self.tk = self.master.tk357 358 359 def configure(self, style, query_opt=None, **kw):360 """Query or sets the default value of the specified option(s) in361 style.362 363 Each key in kw is an option and each value is either a string or364 a sequence identifying the value for that option."""365 if query_opt is not None:366 kw[query_opt] = None367 result = _val_or_dict(self.tk, kw, self._name, "configure", style)368 if result or query_opt:369 return result370 371 372 def map(self, style, query_opt=None, **kw):373 """Query or sets dynamic values of the specified option(s) in374 style.375 376 Each key in kw is an option and each value should be a list or a377 tuple (usually) containing statespecs grouped in tuples, or list,378 or something else of your preference. A statespec is compound of379 one or more states and then a value."""380 if query_opt is not None:381 result = self.tk.call(self._name, "map", style, '-%s' % query_opt)382 return _list_from_statespec(self.tk.splitlist(result))383 384 result = self.tk.call(self._name, "map", style, *_format_mapdict(kw))385 return {k: _list_from_statespec(self.tk.splitlist(v))386 for k, v in _splitdict(self.tk, result).items()}387 388 389 def lookup(self, style, option, state=None, default=None):390 """Returns the value specified for option in style.391 392 If state is specified it is expected to be a sequence of one393 or more states. If the default argument is set, it is used as394 a fallback value in case no specification for option is found."""395 state = ' '.join(state) if state else ''396 397 return self.tk.call(self._name, "lookup", style, '-%s' % option,398 state, default)399 400 401 def layout(self, style, layoutspec=None):402 """Define the widget layout for given style. If layoutspec is403 omitted, return the layout specification for given style.404 405 layoutspec is expected to be a list or an object different than406 None that evaluates to False if you want to "turn off" that style.407 If it is a list (or tuple, or something else), each item should be408 a tuple where the first item is the layout name and the second item409 should have the format described below:410 411 LAYOUTS412 413 A layout can contain the value None, if takes no options, or414 a dict of options specifying how to arrange the element.415 The layout mechanism uses a simplified version of the pack416 geometry manager: given an initial cavity, each element is417 allocated a parcel. Valid options/values are:418 419 side: whichside420 Specifies which side of the cavity to place the421 element; one of top, right, bottom or left. If422 omitted, the element occupies the entire cavity.423 424 sticky: nswe425 Specifies where the element is placed inside its426 allocated parcel.427 428 children: [sublayout... ]429 Specifies a list of elements to place inside the430 element. Each element is a tuple (or other sequence)431 where the first item is the layout name, and the other432 is a LAYOUT."""433 lspec = None434 if layoutspec:435 lspec = _format_layoutlist(layoutspec)[0]436 elif layoutspec is not None: # will disable the layout ({}, '', etc)437 lspec = "null" # could be any other word, but this may make sense438 # when calling layout(style) later439 440 return _list_from_layouttuple(self.tk,441 self.tk.call(self._name, "layout", style, lspec))442 443 444 def element_create(self, elementname, etype, *args, **kw):445 """Create a new element in the current theme of given etype."""446 *specs, opts = _format_elemcreate(etype, False, *args, **kw)447 self.tk.call(self._name, "element", "create", elementname, etype,448 *specs, *opts)449 450 451 def element_names(self):452 """Returns the list of elements defined in the current theme."""453 return tuple(n.lstrip('-') for n in self.tk.splitlist(454 self.tk.call(self._name, "element", "names")))455 456 457 def element_options(self, elementname):458 """Return the list of elementname's options."""459 return tuple(o.lstrip('-') for o in self.tk.splitlist(460 self.tk.call(self._name, "element", "options", elementname)))461 462 463 def theme_create(self, themename, parent=None, settings=None):464 """Creates a new theme.465 466 It is an error if themename already exists. If parent is467 specified, the new theme will inherit styles, elements and468 layouts from the specified parent theme. If settings are present,469 they are expected to have the same syntax used for theme_settings."""470 script = _script_from_settings(settings) if settings else ''471 472 if parent:473 self.tk.call(self._name, "theme", "create", themename,474 "-parent", parent, "-settings", script)475 else:476 self.tk.call(self._name, "theme", "create", themename,477 "-settings", script)478 479 480 def theme_settings(self, themename, settings):481 """Temporarily sets the current theme to themename, apply specified482 settings and then restore the previous theme.483 484 Each key in settings is a style and each value may contain the485 keys 'configure', 'map', 'layout' and 'element create' and they486 are expected to have the same format as specified by the methods487 configure, map, layout and element_create respectively."""488 script = _script_from_settings(settings)489 self.tk.call(self._name, "theme", "settings", themename, script)490 491 492 def theme_names(self):493 """Returns a list of all known themes."""494 return self.tk.splitlist(self.tk.call(self._name, "theme", "names"))495 496 497 def theme_use(self, themename=None):498 """If themename is None, returns the theme in use, otherwise, set499 the current theme to themename, refreshes all widgets and emits500 a <<ThemeChanged>> event."""501 if themename is None:502 # Starting on Tk 8.6, checking this global is no longer needed503 # since it allows doing self.tk.call(self._name, "theme", "use")504 return self.tk.eval("return $ttk::currentTheme")505 506 # using "ttk::setTheme" instead of "ttk::style theme use" causes507 # the variable currentTheme to be updated, also, ttk::setTheme calls508 # "ttk::style theme use" in order to change theme.509 self.tk.call("ttk::setTheme", themename)510 511 512class Widget(tkinter.Widget):513 """Base class for Tk themed widgets."""514 515 def __init__(self, master, widgetname, kw=None):516 """Constructs a Ttk Widget with the parent master.517 518 STANDARD OPTIONS519 520 class, cursor, takefocus, style521 522 SCROLLABLE WIDGET OPTIONS523 524 xscrollcommand, yscrollcommand525 526 LABEL WIDGET OPTIONS527 528 text, textvariable, underline, image, compound, width529 530 WIDGET STATES531 532 active, disabled, focus, pressed, selected, background,533 readonly, alternate, invalid534 """535 master = setup_master(master)536 tkinter.Widget.__init__(self, master, widgetname, kw=kw)537 538 539 def identify(self, x, y):540 """Returns the name of the element at position x, y, or the empty541 string if the point does not lie within any element.542 543 x and y are pixel coordinates relative to the widget."""544 return self.tk.call(self._w, "identify", x, y)545 546 547 def instate(self, statespec, callback=None, *args, **kw):548 """Test the widget's state.549 550 If callback is not specified, returns True if the widget state551 matches statespec and False otherwise. If callback is specified,552 then it will be invoked with *args, **kw if the widget state553 matches statespec. statespec is expected to be a sequence."""554 ret = self.tk.getboolean(555 self.tk.call(self._w, "instate", ' '.join(statespec)))556 if ret and callback is not None:557 return callback(*args, **kw)558 559 return ret560 561 562 def state(self, statespec=None):563 """Modify or inquire widget state.564 565 Widget state is returned if statespec is None, otherwise it is566 set according to the statespec flags and then a new state spec567 is returned indicating which flags were changed. statespec is568 expected to be a sequence."""569 if statespec is not None:570 statespec = ' '.join(statespec)571 572 return self.tk.splitlist(str(self.tk.call(self._w, "state", statespec)))573 574 575class Button(Widget):576 """Ttk Button widget, displays a textual label and/or image, and577 evaluates a command when pressed."""578 579 def __init__(self, master=None, **kw):580 """Construct a Ttk Button widget with the parent master.581 582 STANDARD OPTIONS583 584 class, compound, cursor, image, state, style, takefocus,585 text, textvariable, underline, width586 587 WIDGET-SPECIFIC OPTIONS588 589 command, default, width590 """591 Widget.__init__(self, master, "ttk::button", kw)592 593 594 def invoke(self):595 """Invokes the command associated with the button."""596 return self.tk.call(self._w, "invoke")597 598 599class Checkbutton(Widget):600 """Ttk Checkbutton widget which is either in on- or off-state."""601 602 def __init__(self, master=None, **kw):603 """Construct a Ttk Checkbutton widget with the parent master.604 605 STANDARD OPTIONS606 607 class, compound, cursor, image, state, style, takefocus,608 text, textvariable, underline, width609 610 WIDGET-SPECIFIC OPTIONS611 612 command, offvalue, onvalue, variable613 """614 Widget.__init__(self, master, "ttk::checkbutton", kw)615 616 617 def invoke(self):618 """Toggles between the selected and deselected states and619 invokes the associated command. If the widget is currently620 selected, sets the option variable to the offvalue option621 and deselects the widget; otherwise, sets the option variable622 to the option onvalue.623 624 Returns the result of the associated command."""625 return self.tk.call(self._w, "invoke")626 627 628class Entry(Widget, tkinter.Entry):629 """Ttk Entry widget displays a one-line text string and allows that630 string to be edited by the user."""631 632 def __init__(self, master=None, widget=None, **kw):633 """Constructs a Ttk Entry widget with the parent master.634 635 STANDARD OPTIONS636 637 class, cursor, style, takefocus, xscrollcommand638 639 WIDGET-SPECIFIC OPTIONS640 641 exportselection, invalidcommand, justify, show, state,642 textvariable, validate, validatecommand, width643 644 VALIDATION MODES645 646 none, key, focus, focusin, focusout, all647 """648 Widget.__init__(self, master, widget or "ttk::entry", kw)649 650 651 def bbox(self, index):652 """Return a tuple of (x, y, width, height) which describes the653 bounding box of the character given by index."""654 return self._getints(self.tk.call(self._w, "bbox", index))655 656 657 def identify(self, x, y):658 """Returns the name of the element at position x, y, or the659 empty string if the coordinates are outside the window."""660 return self.tk.call(self._w, "identify", x, y)661 662 663 def validate(self):664 """Force revalidation, independent of the conditions specified665 by the validate option. Returns False if validation fails, True666 if it succeeds. Sets or clears the invalid state accordingly."""667 return self.tk.getboolean(self.tk.call(self._w, "validate"))668 669 670class Combobox(Entry):671 """Ttk Combobox widget combines a text field with a pop-down list of672 values."""673 674 def __init__(self, master=None, **kw):675 """Construct a Ttk Combobox widget with the parent master.676 677 STANDARD OPTIONS678 679 class, cursor, style, takefocus680 681 WIDGET-SPECIFIC OPTIONS682 683 exportselection, justify, height, postcommand, state,684 textvariable, values, width685 """686 Entry.__init__(self, master, "ttk::combobox", **kw)687 688 689 def current(self, newindex=None):690 """If newindex is supplied, sets the combobox value to the691 element at position newindex in the list of values. Otherwise,692 returns the index of the current value in the list of values693 or -1 if the current value does not appear in the list."""694 if newindex is None:695 res = self.tk.call(self._w, "current")696 if res == '':697 return -1698 return self.tk.getint(res)699 return self.tk.call(self._w, "current", newindex)700 701 702 def set(self, value):703 """Sets the value of the combobox to value."""704 self.tk.call(self._w, "set", value)705 706 707class Frame(Widget):708 """Ttk Frame widget is a container, used to group other widgets709 together."""710 711 def __init__(self, master=None, **kw):712 """Construct a Ttk Frame with parent master.713 714 STANDARD OPTIONS715 716 class, cursor, style, takefocus717 718 WIDGET-SPECIFIC OPTIONS719 720 borderwidth, relief, padding, width, height721 """722 Widget.__init__(self, master, "ttk::frame", kw)723 724 725class Label(Widget):726 """Ttk Label widget displays a textual label and/or image."""727 728 def __init__(self, master=None, **kw):729 """Construct a Ttk Label with parent master.730 731 STANDARD OPTIONS732 733 class, compound, cursor, image, style, takefocus, text,734 textvariable, underline, width735 736 WIDGET-SPECIFIC OPTIONS737 738 anchor, background, font, foreground, justify, padding,739 relief, text, wraplength740 """741 Widget.__init__(self, master, "ttk::label", kw)742 743 744class Labelframe(Widget):745 """Ttk Labelframe widget is a container used to group other widgets746 together. It has an optional label, which may be a plain text string747 or another widget."""748 749 def __init__(self, master=None, **kw):750 """Construct a Ttk Labelframe with parent master.751 752 STANDARD OPTIONS753 754 class, cursor, style, takefocus755 756 WIDGET-SPECIFIC OPTIONS757 labelanchor, text, underline, padding, labelwidget, width,758 height759 """760 Widget.__init__(self, master, "ttk::labelframe", kw)761 762LabelFrame = Labelframe # tkinter name compatibility763 764 765class Menubutton(Widget):766 """Ttk Menubutton widget displays a textual label and/or image, and767 displays a menu when pressed."""768 769 def __init__(self, master=None, **kw):770 """Construct a Ttk Menubutton with parent master.771 772 STANDARD OPTIONS773 774 class, compound, cursor, image, state, style, takefocus,775 text, textvariable, underline, width776 777 WIDGET-SPECIFIC OPTIONS778 779 direction, menu780 """781 Widget.__init__(self, master, "ttk::menubutton", kw)782 783 784class Notebook(Widget):785 """Ttk Notebook widget manages a collection of windows and displays786 a single one at a time. Each child window is associated with a tab,787 which the user may select to change the currently-displayed window."""788 789 def __init__(self, master=None, **kw):790 """Construct a Ttk Notebook with parent master.791 792 STANDARD OPTIONS793 794 class, cursor, style, takefocus795 796 WIDGET-SPECIFIC OPTIONS797 798 height, padding, width799 800 TAB OPTIONS801 802 state, sticky, padding, text, image, compound, underline803 804 TAB IDENTIFIERS (tab_id)805 806 The tab_id argument found in several methods may take any of807 the following forms:808 809 * An integer between zero and the number of tabs810 * The name of a child window811 * A positional specification of the form "@x,y", which812 defines the tab813 * The string "current", which identifies the814 currently-selected tab815 * The string "end", which returns the number of tabs (only816 valid for method index)817 """818 Widget.__init__(self, master, "ttk::notebook", kw)819 820 821 def add(self, child, **kw):822 """Adds a new tab to the notebook.823 824 If window is currently managed by the notebook but hidden, it is825 restored to its previous position."""826 self.tk.call(self._w, "add", child, *(_format_optdict(kw)))827 828 829 def forget(self, tab_id):830 """Removes the tab specified by tab_id, unmaps and unmanages the831 associated window."""832 self.tk.call(self._w, "forget", tab_id)833 834 835 def hide(self, tab_id):836 """Hides the tab specified by tab_id.837 838 The tab will not be displayed, but the associated window remains839 managed by the notebook and its configuration remembered. Hidden840 tabs may be restored with the add command."""841 self.tk.call(self._w, "hide", tab_id)842 843 844 def identify(self, x, y):845 """Returns the name of the tab element at position x, y, or the846 empty string if none."""847 return self.tk.call(self._w, "identify", x, y)848 849 850 def index(self, tab_id):851 """Returns the numeric index of the tab specified by tab_id, or852 the total number of tabs if tab_id is the string "end"."""853 return self.tk.getint(self.tk.call(self._w, "index", tab_id))854 855 856 def insert(self, pos, child, **kw):857 """Inserts a pane at the specified position.858 859 pos is either the string end, an integer index, or the name of860 a managed child. If child is already managed by the notebook,861 moves it to the specified position."""862 self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))863 864 865 def select(self, tab_id=None):866 """Selects the specified tab.867 868 The associated child window will be displayed, and the869 previously-selected window (if different) is unmapped. If tab_id870 is omitted, returns the widget name of the currently selected871 pane."""872 return self.tk.call(self._w, "select", tab_id)873 874 875 def tab(self, tab_id, option=None, **kw):876 """Query or modify the options of the specific tab_id.877 878 If kw is not given, returns a dict of the tab option values. If option879 is specified, returns the value of that option. Otherwise, sets the880 options to the corresponding values."""881 if option is not None:882 kw[option] = None883 return _val_or_dict(self.tk, kw, self._w, "tab", tab_id)884 885 886 def tabs(self):887 """Returns a list of windows managed by the notebook."""888 return self.tk.splitlist(self.tk.call(self._w, "tabs") or ())889 890 891 def enable_traversal(self):892 """Enable keyboard traversal for a toplevel window containing893 this notebook.894 895 This will extend the bindings for the toplevel window containing896 this notebook as follows:897 898 Control-Tab: selects the tab following the currently selected899 one900 901 Shift-Control-Tab: selects the tab preceding the currently902 selected one903 904 Alt-K: where K is the mnemonic (underlined) character of any905 tab, will select that tab.906 907 Multiple notebooks in a single toplevel may be enabled for908 traversal, including nested notebooks. However, notebook traversal909 only works properly if all panes are direct children of the910 notebook."""911 # The only, and good, difference I see is about mnemonics, which works912 # after calling this method. Control-Tab and Shift-Control-Tab always913 # works (here at least).914 self.tk.call("ttk::notebook::enableTraversal", self._w)915 916 917class Panedwindow(Widget, tkinter.PanedWindow):918 """Ttk Panedwindow widget displays a number of subwindows, stacked919 either vertically or horizontally."""920 921 def __init__(self, master=None, **kw):922 """Construct a Ttk Panedwindow with parent master.923 924 STANDARD OPTIONS925 926 class, cursor, style, takefocus927 928 WIDGET-SPECIFIC OPTIONS929 930 orient, width, height931 932 PANE OPTIONS933 934 weight935 """936 Widget.__init__(self, master, "ttk::panedwindow", kw)937 938 939 forget = tkinter.PanedWindow.forget # overrides Pack.forget940 941 942 def insert(self, pos, child, **kw):943 """Inserts a pane at the specified positions.944 945 pos is either the string end, and integer index, or the name946 of a child. If child is already managed by the paned window,947 moves it to the specified position."""948 self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))949 950 951 def pane(self, pane, option=None, **kw):952 """Query or modify the options of the specified pane.953 954 pane is either an integer index or the name of a managed subwindow.955 If kw is not given, returns a dict of the pane option values. If956 option is specified then the value for that option is returned.957 Otherwise, sets the options to the corresponding values."""958 if option is not None:959 kw[option] = None960 return _val_or_dict(self.tk, kw, self._w, "pane", pane)961 962 963 def sashpos(self, index, newpos=None):964 """If newpos is specified, sets the position of sash number index.965 966 May adjust the positions of adjacent sashes to ensure that967 positions are monotonically increasing. Sash positions are further968 constrained to be between 0 and the total size of the widget.969 970 Returns the new position of sash number index."""971 return self.tk.getint(self.tk.call(self._w, "sashpos", index, newpos))972 973PanedWindow = Panedwindow # tkinter name compatibility974 975 976class Progressbar(Widget):977 """Ttk Progressbar widget shows the status of a long-running978 operation. They can operate in two modes: determinate mode shows the979 amount completed relative to the total amount of work to be done, and980 indeterminate mode provides an animated display to let the user know981 that something is happening."""982 983 def __init__(self, master=None, **kw):984 """Construct a Ttk Progressbar with parent master.985 986 STANDARD OPTIONS987 988 class, cursor, style, takefocus989 990 WIDGET-SPECIFIC OPTIONS991 992 orient, length, mode, maximum, value, variable, phase993 """994 Widget.__init__(self, master, "ttk::progressbar", kw)995 996 997 def start(self, interval=None):998 """Begin autoincrement mode: schedules a recurring timer event999 that calls method step every interval milliseconds.1000 1001 interval defaults to 50 milliseconds (20 steps/second) if omitted."""1002 self.tk.call(self._w, "start", interval)1003 1004 1005 def step(self, amount=None):1006 """Increments the value option by amount.1007 1008 amount defaults to 1.0 if omitted."""1009 self.tk.call(self._w, "step", amount)1010 1011 1012 def stop(self):1013 """Stop autoincrement mode: cancels any recurring timer event1014 initiated by start."""1015 self.tk.call(self._w, "stop")1016 1017 1018class Radiobutton(Widget):1019 """Ttk Radiobutton widgets are used in groups to show or change a1020 set of mutually-exclusive options."""1021 1022 def __init__(self, master=None, **kw):1023 """Construct a Ttk Radiobutton with parent master.1024 1025 STANDARD OPTIONS1026 1027 class, compound, cursor, image, state, style, takefocus,1028 text, textvariable, underline, width1029 1030 WIDGET-SPECIFIC OPTIONS1031 1032 command, value, variable1033 """1034 Widget.__init__(self, master, "ttk::radiobutton", kw)1035 1036 1037 def invoke(self):1038 """Sets the option variable to the option value, selects the1039 widget, and invokes the associated command.1040 1041 Returns the result of the command, or an empty string if1042 no command is specified."""1043 return self.tk.call(self._w, "invoke")1044 1045 1046class Scale(Widget, tkinter.Scale):1047 """Ttk Scale widget is typically used to control the numeric value of1048 a linked variable that varies uniformly over some range."""1049 1050 def __init__(self, master=None, **kw):1051 """Construct a Ttk Scale with parent master.1052 1053 STANDARD OPTIONS1054 1055 class, cursor, style, takefocus1056 1057 WIDGET-SPECIFIC OPTIONS1058 1059 command, from, length, orient, to, value, variable1060 """1061 Widget.__init__(self, master, "ttk::scale", kw)1062 1063 1064 def configure(self, cnf=None, **kw):1065 """Modify or query scale options.1066 1067 Setting a value for any of the "from", "from_" or "to" options1068 generates a <<RangeChanged>> event."""1069 retval = Widget.configure(self, cnf, **kw)1070 if not isinstance(cnf, (type(None), str)):1071 kw.update(cnf)1072 if any(['from' in kw, 'from_' in kw, 'to' in kw]):1073 self.event_generate('<<RangeChanged>>')1074 return retval1075 1076 1077 def get(self, x=None, y=None):1078 """Get the current value of the value option, or the value1079 corresponding to the coordinates x, y if they are specified.1080 1081 x and y are pixel coordinates relative to the scale widget1082 origin."""1083 return self.tk.call(self._w, 'get', x, y)1084 1085 1086class Scrollbar(Widget, tkinter.Scrollbar):1087 """Ttk Scrollbar controls the viewport of a scrollable widget."""1088 1089 def __init__(self, master=None, **kw):1090 """Construct a Ttk Scrollbar with parent master.1091 1092 STANDARD OPTIONS1093 1094 class, cursor, style, takefocus1095 1096 WIDGET-SPECIFIC OPTIONS1097 1098 command, orient1099 """1100 Widget.__init__(self, master, "ttk::scrollbar", kw)1101 1102 1103class Separator(Widget):1104 """Ttk Separator widget displays a horizontal or vertical separator1105 bar."""1106 1107 def __init__(self, master=None, **kw):1108 """Construct a Ttk Separator with parent master.1109 1110 STANDARD OPTIONS1111 1112 class, cursor, style, takefocus1113 1114 WIDGET-SPECIFIC OPTIONS1115 1116 orient1117 """1118 Widget.__init__(self, master, "ttk::separator", kw)1119 1120 1121class Sizegrip(Widget):1122 """Ttk Sizegrip allows the user to resize the containing toplevel1123 window by pressing and dragging the grip."""1124 1125 def __init__(self, master=None, **kw):1126 """Construct a Ttk Sizegrip with parent master.1127 1128 STANDARD OPTIONS1129 1130 class, cursor, state, style, takefocus1131 """1132 Widget.__init__(self, master, "ttk::sizegrip", kw)1133 1134 1135class Spinbox(Entry):1136 """Ttk Spinbox is an Entry with increment and decrement arrows1137 1138 It is commonly used for number entry or to select from a list of1139 string values.1140 """1141 1142 def __init__(self, master=None, **kw):1143 """Construct a Ttk Spinbox widget with the parent master.1144 1145 STANDARD OPTIONS1146 1147 class, cursor, style, takefocus, validate,1148 validatecommand, xscrollcommand, invalidcommand1149 1150 WIDGET-SPECIFIC OPTIONS1151 1152 to, from_, increment, values, wrap, format, command1153 """1154 Entry.__init__(self, master, "ttk::spinbox", **kw)1155 1156 1157 def set(self, value):1158 """Sets the value of the Spinbox to value."""1159 self.tk.call(self._w, "set", value)1160 1161 1162class Treeview(Widget, tkinter.XView, tkinter.YView):1163 """Ttk Treeview widget displays a hierarchical collection of items.1164 1165 Each item has a textual label, an optional image, and an optional list1166 of data values. The data values are displayed in successive columns1167 after the tree label."""1168 1169 def __init__(self, master=None, **kw):1170 """Construct a Ttk Treeview with parent master.1171 1172 STANDARD OPTIONS1173 1174 class, cursor, style, takefocus, xscrollcommand,1175 yscrollcommand1176 1177 WIDGET-SPECIFIC OPTIONS1178 1179 columns, displaycolumns, height, padding, selectmode, show1180 1181 ITEM OPTIONS1182 1183 text, image, values, open, tags1184 1185 TAG OPTIONS1186 1187 foreground, background, font, image1188 """1189 Widget.__init__(self, master, "ttk::treeview", kw)1190 1191 1192 def bbox(self, item, column=None):1193 """Returns the bounding box (relative to the treeview widget's1194 window) of the specified item in the form x y width height.1195 1196 If column is specified, returns the bounding box of that cell.1197 If the item is not visible (i.e., if it is a descendant of a1198 closed item or is scrolled offscreen), returns an empty string."""1199 return self._getints(self.tk.call(self._w, "bbox", item, column)) or ''1200 