blob: 25e988bd0918878375e75455dfa769204cfc09cd [file] [log] [blame]
Guilherme Polocda93aa2009-01-28 13:09:03 +00001"""Ttk wrapper.
2
3This module provides classes to allow using Tk themed widget set.
4
5Ttk is based on a revised and enhanced version of
6TIP #48 (http://tip.tcl.tk/48) specified style engine.
7
8Its basic idea is to separate, to the extent possible, the code
9implementing a widget's behavior from the code implementing its
10appearance. Widget class bindings are primarily responsible for
11maintaining the widget state and invoking callbacks, all aspects
12of 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", "Style", "Treeview",
23 # Extensions
24 "LabeledScale", "OptionMenu",
25 # functions
Guilherme Polo190c35f2009-02-09 16:09:17 +000026 "tclobjs_to_py", "setup_master"]
Guilherme Polocda93aa2009-01-28 13:09:03 +000027
28import Tkinter
Serhiy Storchakae39ba042013-01-15 18:01:21 +020029from Tkinter import _flatten, _join, _stringify
Guilherme Polocda93aa2009-01-28 13:09:03 +000030
Guilherme Polo8e5e4382009-02-07 02:20:29 +000031# Verify if Tk is new enough to not need the Tile package
Guilherme Polocda93aa2009-01-28 13:09:03 +000032_REQUIRE_TILE = True if Tkinter.TkVersion < 8.5 else False
33
Guilherme Polo8e5e4382009-02-07 02:20:29 +000034def _load_tile(master):
35 if _REQUIRE_TILE:
36 import os
37 tilelib = os.environ.get('TILE_LIBRARY')
38 if tilelib:
Walter Dörwald28277092009-05-04 16:03:03 +000039 # append custom tile path to the list of directories that
Guilherme Polo8e5e4382009-02-07 02:20:29 +000040 # Tcl uses when attempting to resolve packages with the package
41 # command
42 master.tk.eval(
43 'global auto_path; '
44 'lappend auto_path {%s}' % tilelib)
Guilherme Polocda93aa2009-01-28 13:09:03 +000045
Guilherme Polo8e5e4382009-02-07 02:20:29 +000046 master.tk.eval('package require tile') # TclError may be raised here
47 master._tile_loaded = True
Guilherme Polocda93aa2009-01-28 13:09:03 +000048
Serhiy Storchakae39ba042013-01-15 18:01:21 +020049def _format_optvalue(value, script=False):
50 """Internal function."""
51 if script:
52 # if caller passes a Tcl script to tk.call, all the values need to
53 # be grouped into words (arguments to a command in Tcl dialect)
54 value = _stringify(value)
55 elif isinstance(value, (list, tuple)):
56 value = _join(value)
57 return value
58
Guilherme Polocda93aa2009-01-28 13:09:03 +000059def _format_optdict(optdict, script=False, ignore=None):
60 """Formats optdict to a tuple to pass it to tk.call.
61
62 E.g. (script=False):
63 {'foreground': 'blue', 'padding': [1, 2, 3, 4]} returns:
64 ('-foreground', 'blue', '-padding', '1 2 3 4')"""
Guilherme Polocda93aa2009-01-28 13:09:03 +000065
66 opts = []
67 for opt, value in optdict.iteritems():
Serhiy Storchakae39ba042013-01-15 18:01:21 +020068 if not ignore or opt not in ignore:
69 opts.append("-%s" % opt)
70 if value is not None:
71 opts.append(_format_optvalue(value, script))
Guilherme Polocda93aa2009-01-28 13:09:03 +000072
Guilherme Polocda93aa2009-01-28 13:09:03 +000073 return _flatten(opts)
74
Serhiy Storchakae39ba042013-01-15 18:01:21 +020075def _mapdict_values(items):
76 # each value in mapdict is expected to be a sequence, where each item
77 # is another sequence containing a state (or several) and a value
78 # E.g. (script=False):
79 # [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]
80 # returns:
81 # ['active selected', 'grey', 'focus', [1, 2, 3, 4]]
82 opt_val = []
83 for item in items:
84 state = item[:-1]
85 val = item[-1]
86 # hacks for bakward compatibility
87 state[0] # raise IndexError if empty
88 if len(state) == 1:
89 # if it is empty (something that evaluates to False), then
90 # format it to Tcl code to denote the "normal" state
91 state = state[0] or ''
92 else:
93 # group multiple states
94 state = ' '.join(state) # raise TypeError if not str
95 opt_val.append(state)
96 if val is not None:
97 opt_val.append(val)
98 return opt_val
99
Guilherme Polocda93aa2009-01-28 13:09:03 +0000100def _format_mapdict(mapdict, script=False):
101 """Formats mapdict to pass it to tk.call.
102
103 E.g. (script=False):
104 {'expand': [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]}
105
106 returns:
107
108 ('-expand', '{active selected} grey focus {1, 2, 3, 4}')"""
Guilherme Polocda93aa2009-01-28 13:09:03 +0000109
110 opts = []
111 for opt, value in mapdict.iteritems():
Serhiy Storchakae39ba042013-01-15 18:01:21 +0200112 opts.extend(("-%s" % opt,
113 _format_optvalue(_mapdict_values(value), script)))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000114
115 return _flatten(opts)
116
117def _format_elemcreate(etype, script=False, *args, **kw):
118 """Formats args and kw according to the given element factory etype."""
119 spec = None
120 opts = ()
121 if etype in ("image", "vsapi"):
122 if etype == "image": # define an element based on an image
123 # first arg should be the default image name
124 iname = args[0]
125 # next args, if any, are statespec/value pairs which is almost
126 # a mapdict, but we just need the value
Serhiy Storchakae39ba042013-01-15 18:01:21 +0200127 imagespec = _join(_mapdict_values(args[1:]))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000128 spec = "%s %s" % (iname, imagespec)
129
130 else:
131 # define an element whose visual appearance is drawn using the
132 # Microsoft Visual Styles API which is responsible for the
133 # themed styles on Windows XP and Vista.
134 # Availability: Tk 8.6, Windows XP and Vista.
135 class_name, part_id = args[:2]
Serhiy Storchakae39ba042013-01-15 18:01:21 +0200136 statemap = _join(_mapdict_values(args[2:]))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000137 spec = "%s %s %s" % (class_name, part_id, statemap)
138
139 opts = _format_optdict(kw, script)
140
141 elif etype == "from": # clone an element
142 # it expects a themename and optionally an element to clone from,
143 # otherwise it will clone {} (empty element)
144 spec = args[0] # theme name
145 if len(args) > 1: # elementfrom specified
Serhiy Storchakae39ba042013-01-15 18:01:21 +0200146 opts = (_format_optvalue(args[1], script),)
Guilherme Polocda93aa2009-01-28 13:09:03 +0000147
148 if script:
149 spec = '{%s}' % spec
Serhiy Storchakae39ba042013-01-15 18:01:21 +0200150 opts = ' '.join(opts)
Guilherme Polocda93aa2009-01-28 13:09:03 +0000151
152 return spec, opts
153
154def _format_layoutlist(layout, indent=0, indent_size=2):
155 """Formats a layout list so we can pass the result to ttk::style
156 layout and ttk::style settings. Note that the layout doesn't has to
157 be a list necessarily.
158
159 E.g.:
160 [("Menubutton.background", None),
161 ("Menubutton.button", {"children":
162 [("Menubutton.focus", {"children":
163 [("Menubutton.padding", {"children":
164 [("Menubutton.label", {"side": "left", "expand": 1})]
165 })]
166 })]
167 }),
168 ("Menubutton.indicator", {"side": "right"})
169 ]
170
171 returns:
172
173 Menubutton.background
174 Menubutton.button -children {
175 Menubutton.focus -children {
176 Menubutton.padding -children {
177 Menubutton.label -side left -expand 1
178 }
179 }
180 }
181 Menubutton.indicator -side right"""
182 script = []
183
184 for layout_elem in layout:
185 elem, opts = layout_elem
186 opts = opts or {}
Serhiy Storchakae39ba042013-01-15 18:01:21 +0200187 fopts = ' '.join(_format_optdict(opts, True, ("children",)))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000188 head = "%s%s%s" % (' ' * indent, elem, (" %s" % fopts) if fopts else '')
189
190 if "children" in opts:
191 script.append(head + " -children {")
192 indent += indent_size
193 newscript, indent = _format_layoutlist(opts['children'], indent,
194 indent_size)
195 script.append(newscript)
196 indent -= indent_size
197 script.append('%s}' % (' ' * indent))
198 else:
199 script.append(head)
200
201 return '\n'.join(script), indent
202
203def _script_from_settings(settings):
204 """Returns an appropriate script, based on settings, according to
205 theme_settings definition to be used by theme_settings and
206 theme_create."""
207 script = []
208 # a script will be generated according to settings passed, which
209 # will then be evaluated by Tcl
210 for name, opts in settings.iteritems():
211 # will format specific keys according to Tcl code
212 if opts.get('configure'): # format 'configure'
Serhiy Storchakae39ba042013-01-15 18:01:21 +0200213 s = ' '.join(_format_optdict(opts['configure'], True))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000214 script.append("ttk::style configure %s %s;" % (name, s))
215
216 if opts.get('map'): # format 'map'
Serhiy Storchakae39ba042013-01-15 18:01:21 +0200217 s = ' '.join(_format_mapdict(opts['map'], True))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000218 script.append("ttk::style map %s %s;" % (name, s))
219
220 if 'layout' in opts: # format 'layout' which may be empty
221 if not opts['layout']:
222 s = 'null' # could be any other word, but this one makes sense
223 else:
224 s, _ = _format_layoutlist(opts['layout'])
225 script.append("ttk::style layout %s {\n%s\n}" % (name, s))
226
227 if opts.get('element create'): # format 'element create'
228 eopts = opts['element create']
229 etype = eopts[0]
230
231 # find where args end, and where kwargs start
232 argc = 1 # etype was the first one
233 while argc < len(eopts) and not hasattr(eopts[argc], 'iteritems'):
234 argc += 1
235
236 elemargs = eopts[1:argc]
237 elemkw = eopts[argc] if argc < len(eopts) and eopts[argc] else {}
238 spec, opts = _format_elemcreate(etype, True, *elemargs, **elemkw)
239
240 script.append("ttk::style element create %s %s %s %s" % (
241 name, etype, spec, opts))
242
243 return '\n'.join(script)
244
245def _dict_from_tcltuple(ttuple, cut_minus=True):
246 """Break tuple in pairs, format it properly, then build the return
247 dict. If cut_minus is True, the supposed '-' prefixing options will
248 be removed.
249
250 ttuple is expected to contain an even number of elements."""
251 opt_start = 1 if cut_minus else 0
252
253 retdict = {}
254 it = iter(ttuple)
255 for opt, val in zip(it, it):
256 retdict[str(opt)[opt_start:]] = val
257
258 return tclobjs_to_py(retdict)
259
260def _list_from_statespec(stuple):
261 """Construct a list from the given statespec tuple according to the
262 accepted statespec accepted by _format_mapdict."""
263 nval = []
264 for val in stuple:
265 typename = getattr(val, 'typename', None)
266 if typename is None:
267 nval.append(val)
268 else: # this is a Tcl object
269 val = str(val)
270 if typename == 'StateSpec':
271 val = val.split()
272 nval.append(val)
273
274 it = iter(nval)
275 return [_flatten(spec) for spec in zip(it, it)]
276
277def _list_from_layouttuple(ltuple):
278 """Construct a list from the tuple returned by ttk::layout, this is
279 somewhat the reverse of _format_layoutlist."""
280 res = []
281
282 indx = 0
283 while indx < len(ltuple):
284 name = ltuple[indx]
285 opts = {}
286 res.append((name, opts))
287 indx += 1
288
289 while indx < len(ltuple): # grab name's options
290 opt, val = ltuple[indx:indx + 2]
291 if not opt.startswith('-'): # found next name
292 break
293
294 opt = opt[1:] # remove the '-' from the option
295 indx += 2
296
297 if opt == 'children':
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200298 if (Tkinter._default_root and
299 not Tkinter._default_root.wantobjects()):
300 val = Tkinter._default_root.splitlist(val)
Guilherme Polocda93aa2009-01-28 13:09:03 +0000301 val = _list_from_layouttuple(val)
302
303 opts[opt] = val
304
305 return res
306
307def _val_or_dict(options, func, *args):
308 """Format options then call func with args and options and return
309 the appropriate result.
310
311 If no option is specified, a dict is returned. If a option is
312 specified with the None value, the value for that option is returned.
313 Otherwise, the function just sets the passed options and the caller
314 shouldn't be expecting a return value anyway."""
315 options = _format_optdict(options)
316 res = func(*(args + options))
317
318 if len(options) % 2: # option specified without a value, return its value
319 return res
320
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200321 if Tkinter._default_root:
322 res = Tkinter._default_root.splitlist(res)
Guilherme Polocda93aa2009-01-28 13:09:03 +0000323 return _dict_from_tcltuple(res)
324
325def _convert_stringval(value):
326 """Converts a value to, hopefully, a more appropriate Python object."""
327 value = unicode(value)
328 try:
329 value = int(value)
330 except (ValueError, TypeError):
331 pass
332
333 return value
334
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200335def _to_number(x):
336 if isinstance(x, str):
337 if '.' in x:
338 x = float(x)
339 else:
340 x = int(x)
341 return x
342
Guilherme Polocda93aa2009-01-28 13:09:03 +0000343def tclobjs_to_py(adict):
344 """Returns adict with its values converted from Tcl objects to Python
345 objects."""
346 for opt, val in adict.iteritems():
347 if val and hasattr(val, '__len__') and not isinstance(val, basestring):
348 if getattr(val[0], 'typename', None) == 'StateSpec':
349 val = _list_from_statespec(val)
350 else:
351 val = map(_convert_stringval, val)
352
353 elif hasattr(val, 'typename'): # some other (single) Tcl object
354 val = _convert_stringval(val)
355
356 adict[opt] = val
357
358 return adict
359
Guilherme Polo190c35f2009-02-09 16:09:17 +0000360def setup_master(master=None):
361 """If master is not None, itself is returned. If master is None,
362 the default master is returned if there is one, otherwise a new
363 master is created and returned.
364
365 If it is not allowed to use the default root and master is None,
366 RuntimeError is raised."""
367 if master is None:
368 if Tkinter._support_default_root:
369 master = Tkinter._default_root or Tkinter.Tk()
370 else:
371 raise RuntimeError(
372 "No master specified and Tkinter is "
373 "configured to not support default root")
374 return master
375
Guilherme Polocda93aa2009-01-28 13:09:03 +0000376
377class Style(object):
378 """Manipulate style database."""
379
380 _name = "ttk::style"
381
382 def __init__(self, master=None):
Guilherme Polo190c35f2009-02-09 16:09:17 +0000383 master = setup_master(master)
Guilherme Polo8e5e4382009-02-07 02:20:29 +0000384
385 if not getattr(master, '_tile_loaded', False):
386 # Load tile now, if needed
387 _load_tile(master)
Guilherme Polocda93aa2009-01-28 13:09:03 +0000388
389 self.master = master
390 self.tk = self.master.tk
391
392
393 def configure(self, style, query_opt=None, **kw):
394 """Query or sets the default value of the specified option(s) in
395 style.
396
397 Each key in kw is an option and each value is either a string or
398 a sequence identifying the value for that option."""
399 if query_opt is not None:
400 kw[query_opt] = None
401 return _val_or_dict(kw, self.tk.call, self._name, "configure", style)
402
403
404 def map(self, style, query_opt=None, **kw):
405 """Query or sets dynamic values of the specified option(s) in
406 style.
407
408 Each key in kw is an option and each value should be a list or a
409 tuple (usually) containing statespecs grouped in tuples, or list,
410 or something else of your preference. A statespec is compound of
411 one or more states and then a value."""
412 if query_opt is not None:
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200413 return _list_from_statespec(self.tk.splitlist(
414 self.tk.call(self._name, "map", style, '-%s' % query_opt)))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000415
416 return _dict_from_tcltuple(
417 self.tk.call(self._name, "map", style, *(_format_mapdict(kw))))
418
419
420 def lookup(self, style, option, state=None, default=None):
421 """Returns the value specified for option in style.
422
423 If state is specified it is expected to be a sequence of one
424 or more states. If the default argument is set, it is used as
425 a fallback value in case no specification for option is found."""
426 state = ' '.join(state) if state else ''
427
428 return self.tk.call(self._name, "lookup", style, '-%s' % option,
429 state, default)
430
431
432 def layout(self, style, layoutspec=None):
433 """Define the widget layout for given style. If layoutspec is
434 omitted, return the layout specification for given style.
435
436 layoutspec is expected to be a list or an object different than
437 None that evaluates to False if you want to "turn off" that style.
438 If it is a list (or tuple, or something else), each item should be
439 a tuple where the first item is the layout name and the second item
440 should have the format described below:
441
442 LAYOUTS
443
444 A layout can contain the value None, if takes no options, or
445 a dict of options specifying how to arrange the element.
446 The layout mechanism uses a simplified version of the pack
447 geometry manager: given an initial cavity, each element is
448 allocated a parcel. Valid options/values are:
449
450 side: whichside
451 Specifies which side of the cavity to place the
452 element; one of top, right, bottom or left. If
453 omitted, the element occupies the entire cavity.
454
455 sticky: nswe
456 Specifies where the element is placed inside its
457 allocated parcel.
458
459 children: [sublayout... ]
460 Specifies a list of elements to place inside the
461 element. Each element is a tuple (or other sequence)
462 where the first item is the layout name, and the other
463 is a LAYOUT."""
464 lspec = None
465 if layoutspec:
466 lspec = _format_layoutlist(layoutspec)[0]
467 elif layoutspec is not None: # will disable the layout ({}, '', etc)
468 lspec = "null" # could be any other word, but this may make sense
469 # when calling layout(style) later
470
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200471 return _list_from_layouttuple(self.tk.splitlist(
472 self.tk.call(self._name, "layout", style, lspec)))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000473
474
475 def element_create(self, elementname, etype, *args, **kw):
476 """Create a new element in the current theme of given etype."""
477 spec, opts = _format_elemcreate(etype, False, *args, **kw)
478 self.tk.call(self._name, "element", "create", elementname, etype,
479 spec, *opts)
480
481
482 def element_names(self):
483 """Returns the list of elements defined in the current theme."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200484 return self.tk.splitlist(self.tk.call(self._name, "element", "names"))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000485
486
487 def element_options(self, elementname):
488 """Return the list of elementname's options."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200489 return self.tk.splitlist(self.tk.call(self._name, "element", "options", elementname))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000490
491
492 def theme_create(self, themename, parent=None, settings=None):
493 """Creates a new theme.
494
495 It is an error if themename already exists. If parent is
496 specified, the new theme will inherit styles, elements and
497 layouts from the specified parent theme. If settings are present,
498 they are expected to have the same syntax used for theme_settings."""
499 script = _script_from_settings(settings) if settings else ''
500
501 if parent:
502 self.tk.call(self._name, "theme", "create", themename,
503 "-parent", parent, "-settings", script)
504 else:
505 self.tk.call(self._name, "theme", "create", themename,
506 "-settings", script)
507
508
509 def theme_settings(self, themename, settings):
510 """Temporarily sets the current theme to themename, apply specified
511 settings and then restore the previous theme.
512
513 Each key in settings is a style and each value may contain the
514 keys 'configure', 'map', 'layout' and 'element create' and they
515 are expected to have the same format as specified by the methods
516 configure, map, layout and element_create respectively."""
517 script = _script_from_settings(settings)
518 self.tk.call(self._name, "theme", "settings", themename, script)
519
520
521 def theme_names(self):
522 """Returns a list of all known themes."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200523 return self.tk.splitlist(self.tk.call(self._name, "theme", "names"))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000524
525
526 def theme_use(self, themename=None):
527 """If themename is None, returns the theme in use, otherwise, set
528 the current theme to themename, refreshes all widgets and emits
529 a <<ThemeChanged>> event."""
530 if themename is None:
531 # Starting on Tk 8.6, checking this global is no longer needed
532 # since it allows doing self.tk.call(self._name, "theme", "use")
533 return self.tk.eval("return $ttk::currentTheme")
534
535 # using "ttk::setTheme" instead of "ttk::style theme use" causes
536 # the variable currentTheme to be updated, also, ttk::setTheme calls
537 # "ttk::style theme use" in order to change theme.
538 self.tk.call("ttk::setTheme", themename)
539
540
541class Widget(Tkinter.Widget):
542 """Base class for Tk themed widgets."""
543
544 def __init__(self, master, widgetname, kw=None):
545 """Constructs a Ttk Widget with the parent master.
546
547 STANDARD OPTIONS
548
549 class, cursor, takefocus, style
550
551 SCROLLABLE WIDGET OPTIONS
552
553 xscrollcommand, yscrollcommand
554
555 LABEL WIDGET OPTIONS
556
557 text, textvariable, underline, image, compound, width
558
559 WIDGET STATES
560
561 active, disabled, focus, pressed, selected, background,
562 readonly, alternate, invalid
563 """
Guilherme Polo190c35f2009-02-09 16:09:17 +0000564 master = setup_master(master)
Guilherme Polo8e5e4382009-02-07 02:20:29 +0000565 if not getattr(master, '_tile_loaded', False):
566 # Load tile now, if needed
567 _load_tile(master)
Guilherme Polocda93aa2009-01-28 13:09:03 +0000568 Tkinter.Widget.__init__(self, master, widgetname, kw=kw)
569
570
571 def identify(self, x, y):
572 """Returns the name of the element at position x, y, or the empty
573 string if the point does not lie within any element.
574
575 x and y are pixel coordinates relative to the widget."""
576 return self.tk.call(self._w, "identify", x, y)
577
578
579 def instate(self, statespec, callback=None, *args, **kw):
580 """Test the widget's state.
581
582 If callback is not specified, returns True if the widget state
583 matches statespec and False otherwise. If callback is specified,
584 then it will be invoked with *args, **kw if the widget state
585 matches statespec. statespec is expected to be a sequence."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200586 ret = self.tk.getboolean(
587 self.tk.call(self._w, "instate", ' '.join(statespec)))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000588 if ret and callback:
589 return callback(*args, **kw)
590
591 return bool(ret)
592
593
594 def state(self, statespec=None):
595 """Modify or inquire widget state.
596
597 Widget state is returned if statespec is None, otherwise it is
598 set according to the statespec flags and then a new state spec
599 is returned indicating which flags were changed. statespec is
600 expected to be a sequence."""
601 if statespec is not None:
602 statespec = ' '.join(statespec)
603
604 return self.tk.splitlist(str(self.tk.call(self._w, "state", statespec)))
605
606
607class Button(Widget):
608 """Ttk Button widget, displays a textual label and/or image, and
609 evaluates a command when pressed."""
610
611 def __init__(self, master=None, **kw):
612 """Construct a Ttk Button widget with the parent master.
613
614 STANDARD OPTIONS
615
616 class, compound, cursor, image, state, style, takefocus,
617 text, textvariable, underline, width
618
619 WIDGET-SPECIFIC OPTIONS
620
621 command, default, width
622 """
623 Widget.__init__(self, master, "ttk::button", kw)
624
625
626 def invoke(self):
627 """Invokes the command associated with the button."""
628 return self.tk.call(self._w, "invoke")
629
630
631class Checkbutton(Widget):
632 """Ttk Checkbutton widget which is either in on- or off-state."""
633
634 def __init__(self, master=None, **kw):
635 """Construct a Ttk Checkbutton widget with the parent master.
636
637 STANDARD OPTIONS
638
639 class, compound, cursor, image, state, style, takefocus,
640 text, textvariable, underline, width
641
642 WIDGET-SPECIFIC OPTIONS
643
644 command, offvalue, onvalue, variable
645 """
646 Widget.__init__(self, master, "ttk::checkbutton", kw)
647
648
649 def invoke(self):
650 """Toggles between the selected and deselected states and
651 invokes the associated command. If the widget is currently
652 selected, sets the option variable to the offvalue option
653 and deselects the widget; otherwise, sets the option variable
654 to the option onvalue.
655
656 Returns the result of the associated command."""
657 return self.tk.call(self._w, "invoke")
658
659
660class Entry(Widget, Tkinter.Entry):
661 """Ttk Entry widget displays a one-line text string and allows that
662 string to be edited by the user."""
663
664 def __init__(self, master=None, widget=None, **kw):
665 """Constructs a Ttk Entry widget with the parent master.
666
667 STANDARD OPTIONS
668
669 class, cursor, style, takefocus, xscrollcommand
670
671 WIDGET-SPECIFIC OPTIONS
672
673 exportselection, invalidcommand, justify, show, state,
674 textvariable, validate, validatecommand, width
675
676 VALIDATION MODES
677
678 none, key, focus, focusin, focusout, all
679 """
680 Widget.__init__(self, master, widget or "ttk::entry", kw)
681
682
683 def bbox(self, index):
684 """Return a tuple of (x, y, width, height) which describes the
685 bounding box of the character given by index."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200686 return self._getints(self.tk.call(self._w, "bbox", index))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000687
688
689 def identify(self, x, y):
690 """Returns the name of the element at position x, y, or the
691 empty string if the coordinates are outside the window."""
692 return self.tk.call(self._w, "identify", x, y)
693
694
695 def validate(self):
696 """Force revalidation, independent of the conditions specified
697 by the validate option. Returns False if validation fails, True
698 if it succeeds. Sets or clears the invalid state accordingly."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200699 return bool(self.tk.getboolean(self.tk.call(self._w, "validate")))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000700
701
702class Combobox(Entry):
703 """Ttk Combobox widget combines a text field with a pop-down list of
704 values."""
705
706 def __init__(self, master=None, **kw):
707 """Construct a Ttk Combobox widget with the parent master.
708
709 STANDARD OPTIONS
710
711 class, cursor, style, takefocus
712
713 WIDGET-SPECIFIC OPTIONS
714
715 exportselection, justify, height, postcommand, state,
716 textvariable, values, width
717 """
Guilherme Polocda93aa2009-01-28 13:09:03 +0000718 Entry.__init__(self, master, "ttk::combobox", **kw)
719
720
Guilherme Polocda93aa2009-01-28 13:09:03 +0000721 def current(self, newindex=None):
722 """If newindex is supplied, sets the combobox value to the
723 element at position newindex in the list of values. Otherwise,
724 returns the index of the current value in the list of values
725 or -1 if the current value does not appear in the list."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200726 if newindex is None:
727 return self.tk.getint(self.tk.call(self._w, "current"))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000728 return self.tk.call(self._w, "current", newindex)
729
730
731 def set(self, value):
732 """Sets the value of the combobox to value."""
733 self.tk.call(self._w, "set", value)
734
735
736class Frame(Widget):
737 """Ttk Frame widget is a container, used to group other widgets
738 together."""
739
740 def __init__(self, master=None, **kw):
741 """Construct a Ttk Frame with parent master.
742
743 STANDARD OPTIONS
744
745 class, cursor, style, takefocus
746
747 WIDGET-SPECIFIC OPTIONS
748
749 borderwidth, relief, padding, width, height
750 """
751 Widget.__init__(self, master, "ttk::frame", kw)
752
753
754class Label(Widget):
755 """Ttk Label widget displays a textual label and/or image."""
756
757 def __init__(self, master=None, **kw):
758 """Construct a Ttk Label with parent master.
759
760 STANDARD OPTIONS
761
762 class, compound, cursor, image, style, takefocus, text,
763 textvariable, underline, width
764
765 WIDGET-SPECIFIC OPTIONS
766
767 anchor, background, font, foreground, justify, padding,
768 relief, text, wraplength
769 """
770 Widget.__init__(self, master, "ttk::label", kw)
771
772
773class Labelframe(Widget):
774 """Ttk Labelframe widget is a container used to group other widgets
775 together. It has an optional label, which may be a plain text string
776 or another widget."""
777
778 def __init__(self, master=None, **kw):
779 """Construct a Ttk Labelframe with parent master.
780
781 STANDARD OPTIONS
782
783 class, cursor, style, takefocus
784
785 WIDGET-SPECIFIC OPTIONS
786 labelanchor, text, underline, padding, labelwidget, width,
787 height
788 """
789 Widget.__init__(self, master, "ttk::labelframe", kw)
790
791LabelFrame = Labelframe # Tkinter name compatibility
792
793
794class Menubutton(Widget):
795 """Ttk Menubutton widget displays a textual label and/or image, and
796 displays a menu when pressed."""
797
798 def __init__(self, master=None, **kw):
799 """Construct a Ttk Menubutton with parent master.
800
801 STANDARD OPTIONS
802
803 class, compound, cursor, image, state, style, takefocus,
804 text, textvariable, underline, width
805
806 WIDGET-SPECIFIC OPTIONS
807
808 direction, menu
809 """
810 Widget.__init__(self, master, "ttk::menubutton", kw)
811
812
813class Notebook(Widget):
814 """Ttk Notebook widget manages a collection of windows and displays
815 a single one at a time. Each child window is associated with a tab,
816 which the user may select to change the currently-displayed window."""
817
818 def __init__(self, master=None, **kw):
819 """Construct a Ttk Notebook with parent master.
820
821 STANDARD OPTIONS
822
823 class, cursor, style, takefocus
824
825 WIDGET-SPECIFIC OPTIONS
826
827 height, padding, width
828
829 TAB OPTIONS
830
831 state, sticky, padding, text, image, compound, underline
832
833 TAB IDENTIFIERS (tab_id)
834
835 The tab_id argument found in several methods may take any of
836 the following forms:
837
838 * An integer between zero and the number of tabs
839 * The name of a child window
840 * A positional specification of the form "@x,y", which
841 defines the tab
842 * The string "current", which identifies the
843 currently-selected tab
844 * The string "end", which returns the number of tabs (only
845 valid for method index)
846 """
847 Widget.__init__(self, master, "ttk::notebook", kw)
848
849
850 def add(self, child, **kw):
851 """Adds a new tab to the notebook.
852
853 If window is currently managed by the notebook but hidden, it is
854 restored to its previous position."""
855 self.tk.call(self._w, "add", child, *(_format_optdict(kw)))
856
857
858 def forget(self, tab_id):
859 """Removes the tab specified by tab_id, unmaps and unmanages the
860 associated window."""
861 self.tk.call(self._w, "forget", tab_id)
862
863
864 def hide(self, tab_id):
865 """Hides the tab specified by tab_id.
866
867 The tab will not be displayed, but the associated window remains
868 managed by the notebook and its configuration remembered. Hidden
869 tabs may be restored with the add command."""
870 self.tk.call(self._w, "hide", tab_id)
871
872
873 def identify(self, x, y):
874 """Returns the name of the tab element at position x, y, or the
875 empty string if none."""
876 return self.tk.call(self._w, "identify", x, y)
877
878
879 def index(self, tab_id):
880 """Returns the numeric index of the tab specified by tab_id, or
881 the total number of tabs if tab_id is the string "end"."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200882 return self.tk.getint(self.tk.call(self._w, "index", tab_id))
Guilherme Polocda93aa2009-01-28 13:09:03 +0000883
884
885 def insert(self, pos, child, **kw):
886 """Inserts a pane at the specified position.
887
888 pos is either the string end, an integer index, or the name of
889 a managed child. If child is already managed by the notebook,
890 moves it to the specified position."""
891 self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
892
893
894 def select(self, tab_id=None):
895 """Selects the specified tab.
896
897 The associated child window will be displayed, and the
898 previously-selected window (if different) is unmapped. If tab_id
899 is omitted, returns the widget name of the currently selected
900 pane."""
901 return self.tk.call(self._w, "select", tab_id)
902
903
904 def tab(self, tab_id, option=None, **kw):
905 """Query or modify the options of the specific tab_id.
906
907 If kw is not given, returns a dict of the tab option values. If option
908 is specified, returns the value of that option. Otherwise, sets the
909 options to the corresponding values."""
910 if option is not None:
911 kw[option] = None
912 return _val_or_dict(kw, self.tk.call, self._w, "tab", tab_id)
913
914
915 def tabs(self):
916 """Returns a list of windows managed by the notebook."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +0200917 return self.tk.splitlist(self.tk.call(self._w, "tabs") or ())
Guilherme Polocda93aa2009-01-28 13:09:03 +0000918
919
920 def enable_traversal(self):
921 """Enable keyboard traversal for a toplevel window containing
922 this notebook.
923
924 This will extend the bindings for the toplevel window containing
925 this notebook as follows:
926
927 Control-Tab: selects the tab following the currently selected
928 one
929
930 Shift-Control-Tab: selects the tab preceding the currently
931 selected one
932
933 Alt-K: where K is the mnemonic (underlined) character of any
934 tab, will select that tab.
935
936 Multiple notebooks in a single toplevel may be enabled for
937 traversal, including nested notebooks. However, notebook traversal
938 only works properly if all panes are direct children of the
939 notebook."""
940 # The only, and good, difference I see is about mnemonics, which works
941 # after calling this method. Control-Tab and Shift-Control-Tab always
942 # works (here at least).
943 self.tk.call("ttk::notebook::enableTraversal", self._w)
944
945
946class Panedwindow(Widget, Tkinter.PanedWindow):
947 """Ttk Panedwindow widget displays a number of subwindows, stacked
948 either vertically or horizontally."""
949
950 def __init__(self, master=None, **kw):
951 """Construct a Ttk Panedwindow with parent master.
952
953 STANDARD OPTIONS
954
955 class, cursor, style, takefocus
956
957 WIDGET-SPECIFIC OPTIONS
958
959 orient, width, height
960
961 PANE OPTIONS
962
963 weight
964 """
965 Widget.__init__(self, master, "ttk::panedwindow", kw)
966
967
968 forget = Tkinter.PanedWindow.forget # overrides Pack.forget
969
970
971 def insert(self, pos, child, **kw):
972 """Inserts a pane at the specified positions.
973
974 pos is either the string end, and integer index, or the name
975 of a child. If child is already managed by the paned window,
976 moves it to the specified position."""
977 self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
978
979
980 def pane(self, pane, option=None, **kw):
981 """Query or modify the options of the specified pane.
982
983 pane is either an integer index or the name of a managed subwindow.
984 If kw is not given, returns a dict of the pane option values. If
985 option is specified then the value for that option is returned.
Ezio Melotti24b07bc2011-03-15 18:55:01 +0200986 Otherwise, sets the options to the corresponding values."""
Guilherme Polocda93aa2009-01-28 13:09:03 +0000987 if option is not None:
988 kw[option] = None
989 return _val_or_dict(kw, self.tk.call, self._w, "pane", pane)
990
991
992 def sashpos(self, index, newpos=None):
993 """If newpos is specified, sets the position of sash number index.
994
995 May adjust the positions of adjacent sashes to ensure that
996 positions are monotonically increasing. Sash positions are further
997 constrained to be between 0 and the total size of the widget.
998
999 Returns the new position of sash number index."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +02001000 return self.tk.getint(self.tk.call(self._w, "sashpos", index, newpos))
Guilherme Polocda93aa2009-01-28 13:09:03 +00001001
1002PanedWindow = Panedwindow # Tkinter name compatibility
1003
1004
1005class Progressbar(Widget):
1006 """Ttk Progressbar widget shows the status of a long-running
1007 operation. They can operate in two modes: determinate mode shows the
1008 amount completed relative to the total amount of work to be done, and
1009 indeterminate mode provides an animated display to let the user know
1010 that something is happening."""
1011
1012 def __init__(self, master=None, **kw):
1013 """Construct a Ttk Progressbar with parent master.
1014
1015 STANDARD OPTIONS
1016
1017 class, cursor, style, takefocus
1018
1019 WIDGET-SPECIFIC OPTIONS
1020
1021 orient, length, mode, maximum, value, variable, phase
1022 """
1023 Widget.__init__(self, master, "ttk::progressbar", kw)
1024
1025
1026 def start(self, interval=None):
1027 """Begin autoincrement mode: schedules a recurring timer event
1028 that calls method step every interval milliseconds.
1029
1030 interval defaults to 50 milliseconds (20 steps/second) if ommited."""
1031 self.tk.call(self._w, "start", interval)
1032
1033
1034 def step(self, amount=None):
1035 """Increments the value option by amount.
1036
1037 amount defaults to 1.0 if omitted."""
1038 self.tk.call(self._w, "step", amount)
1039
1040
1041 def stop(self):
1042 """Stop autoincrement mode: cancels any recurring timer event
1043 initiated by start."""
1044 self.tk.call(self._w, "stop")
1045
1046
1047class Radiobutton(Widget):
1048 """Ttk Radiobutton widgets are used in groups to show or change a
1049 set of mutually-exclusive options."""
1050
1051 def __init__(self, master=None, **kw):
1052 """Construct a Ttk Radiobutton with parent master.
1053
1054 STANDARD OPTIONS
1055
1056 class, compound, cursor, image, state, style, takefocus,
1057 text, textvariable, underline, width
1058
1059 WIDGET-SPECIFIC OPTIONS
1060
1061 command, value, variable
1062 """
1063 Widget.__init__(self, master, "ttk::radiobutton", kw)
1064
1065
1066 def invoke(self):
1067 """Sets the option variable to the option value, selects the
1068 widget, and invokes the associated command.
1069
1070 Returns the result of the command, or an empty string if
1071 no command is specified."""
1072 return self.tk.call(self._w, "invoke")
1073
1074
1075class Scale(Widget, Tkinter.Scale):
1076 """Ttk Scale widget is typically used to control the numeric value of
1077 a linked variable that varies uniformly over some range."""
1078
1079 def __init__(self, master=None, **kw):
1080 """Construct a Ttk Scale with parent master.
1081
1082 STANDARD OPTIONS
1083
1084 class, cursor, style, takefocus
1085
1086 WIDGET-SPECIFIC OPTIONS
1087
1088 command, from, length, orient, to, value, variable
1089 """
1090 Widget.__init__(self, master, "ttk::scale", kw)
1091
1092
1093 def configure(self, cnf=None, **kw):
1094 """Modify or query scale options.
1095
1096 Setting a value for any of the "from", "from_" or "to" options
1097 generates a <<RangeChanged>> event."""
1098 if cnf:
1099 kw.update(cnf)
1100 Widget.configure(self, **kw)
1101 if any(['from' in kw, 'from_' in kw, 'to' in kw]):
1102 self.event_generate('<<RangeChanged>>')
1103
1104
1105 def get(self, x=None, y=None):
1106 """Get the current value of the value option, or the value
1107 corresponding to the coordinates x, y if they are specified.
1108
1109 x and y are pixel coordinates relative to the scale widget
1110 origin."""
1111 return self.tk.call(self._w, 'get', x, y)
1112
1113
1114class Scrollbar(Widget, Tkinter.Scrollbar):
1115 """Ttk Scrollbar controls the viewport of a scrollable widget."""
1116
1117 def __init__(self, master=None, **kw):
1118 """Construct a Ttk Scrollbar with parent master.
1119
1120 STANDARD OPTIONS
1121
1122 class, cursor, style, takefocus
1123
1124 WIDGET-SPECIFIC OPTIONS
1125
1126 command, orient
1127 """
1128 Widget.__init__(self, master, "ttk::scrollbar", kw)
1129
1130
1131class Separator(Widget):
1132 """Ttk Separator widget displays a horizontal or vertical separator
1133 bar."""
1134
1135 def __init__(self, master=None, **kw):
1136 """Construct a Ttk Separator with parent master.
1137
1138 STANDARD OPTIONS
1139
1140 class, cursor, style, takefocus
1141
1142 WIDGET-SPECIFIC OPTIONS
1143
1144 orient
1145 """
1146 Widget.__init__(self, master, "ttk::separator", kw)
1147
1148
1149class Sizegrip(Widget):
1150 """Ttk Sizegrip allows the user to resize the containing toplevel
1151 window by pressing and dragging the grip."""
1152
1153 def __init__(self, master=None, **kw):
1154 """Construct a Ttk Sizegrip with parent master.
1155
1156 STANDARD OPTIONS
1157
1158 class, cursor, state, style, takefocus
1159 """
1160 Widget.__init__(self, master, "ttk::sizegrip", kw)
1161
1162
Guilherme Poloe45f0172009-08-14 14:36:45 +00001163class Treeview(Widget, Tkinter.XView, Tkinter.YView):
Guilherme Polocda93aa2009-01-28 13:09:03 +00001164 """Ttk Treeview widget displays a hierarchical collection of items.
1165
1166 Each item has a textual label, an optional image, and an optional list
1167 of data values. The data values are displayed in successive columns
1168 after the tree label."""
1169
1170 def __init__(self, master=None, **kw):
1171 """Construct a Ttk Treeview with parent master.
1172
1173 STANDARD OPTIONS
1174
1175 class, cursor, style, takefocus, xscrollcommand,
1176 yscrollcommand
1177
1178 WIDGET-SPECIFIC OPTIONS
1179
1180 columns, displaycolumns, height, padding, selectmode, show
1181
1182 ITEM OPTIONS
1183
1184 text, image, values, open, tags
1185
1186 TAG OPTIONS
1187
1188 foreground, background, font, image
1189 """
1190 Widget.__init__(self, master, "ttk::treeview", kw)
1191
1192
1193 def bbox(self, item, column=None):
1194 """Returns the bounding box (relative to the treeview widget's
1195 window) of the specified item in the form x y width height.
1196
1197 If column is specified, returns the bounding box of that cell.
1198 If the item is not visible (i.e., if it is a descendant of a
1199 closed item or is scrolled offscreen), returns an empty string."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +02001200 return self._getints(self.tk.call(self._w, "bbox", item, column)) or ''
Guilherme Polocda93aa2009-01-28 13:09:03 +00001201
1202
1203 def get_children(self, item=None):
1204 """Returns a tuple of children belonging to item.
1205
1206 If item is not specified, returns root children."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +02001207 return self.tk.splitlist(
1208 self.tk.call(self._w, "children", item or '') or ())
Guilherme Polocda93aa2009-01-28 13:09:03 +00001209
1210
1211 def set_children(self, item, *newchildren):
1212 """Replaces item's child with newchildren.
1213
1214 Children present in item that are not present in newchildren
1215 are detached from tree. No items in newchildren may be an
1216 ancestor of item."""
1217 self.tk.call(self._w, "children", item, newchildren)
1218
1219
1220 def column(self, column, option=None, **kw):
1221 """Query or modify the options for the specified column.
1222
1223 If kw is not given, returns a dict of the column option values. If
1224 option is specified then the value for that option is returned.
1225 Otherwise, sets the options to the corresponding values."""
1226 if option is not None:
1227 kw[option] = None
1228 return _val_or_dict(kw, self.tk.call, self._w, "column", column)
1229
1230
1231 def delete(self, *items):
1232 """Delete all specified items and all their descendants. The root
1233 item may not be deleted."""
1234 self.tk.call(self._w, "delete", items)
1235
1236
1237 def detach(self, *items):
1238 """Unlinks all of the specified items from the tree.
1239
1240 The items and all of their descendants are still present, and may
1241 be reinserted at another point in the tree, but will not be
1242 displayed. The root item may not be detached."""
1243 self.tk.call(self._w, "detach", items)
1244
1245
1246 def exists(self, item):
Georg Brandlf14a2bf2012-04-04 20:19:09 +02001247 """Returns True if the specified item is present in the tree,
Guilherme Polocda93aa2009-01-28 13:09:03 +00001248 False otherwise."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +02001249 return bool(self.tk.getboolean(self.tk.call(self._w, "exists", item)))
Guilherme Polocda93aa2009-01-28 13:09:03 +00001250
1251
1252 def focus(self, item=None):
1253 """If item is specified, sets the focus item to item. Otherwise,
1254 returns the current focus item, or '' if there is none."""
1255 return self.tk.call(self._w, "focus", item)
1256
1257
1258 def heading(self, column, option=None, **kw):
1259 """Query or modify the heading options for the specified column.
1260
1261 If kw is not given, returns a dict of the heading option values. If
1262 option is specified then the value for that option is returned.
1263 Otherwise, sets the options to the corresponding values.
1264
1265 Valid options/values are:
1266 text: text
1267 The text to display in the column heading
1268 image: image_name
1269 Specifies an image to display to the right of the column
1270 heading
1271 anchor: anchor
1272 Specifies how the heading text should be aligned. One of
1273 the standard Tk anchor values
1274 command: callback
1275 A callback to be invoked when the heading label is
1276 pressed.
1277
1278 To configure the tree column heading, call this with column = "#0" """
1279 cmd = kw.get('command')
1280 if cmd and not isinstance(cmd, basestring):
1281 # callback not registered yet, do it now
1282 kw['command'] = self.master.register(cmd, self._substitute)
1283
1284 if option is not None:
1285 kw[option] = None
1286
1287 return _val_or_dict(kw, self.tk.call, self._w, 'heading', column)
1288
1289
1290 def identify(self, component, x, y):
1291 """Returns a description of the specified component under the
1292 point given by x and y, or the empty string if no such component
1293 is present at that position."""
1294 return self.tk.call(self._w, "identify", component, x, y)
1295
1296
1297 def identify_row(self, y):
1298 """Returns the item ID of the item at position y."""
1299 return self.identify("row", 0, y)
1300
1301
1302 def identify_column(self, x):
1303 """Returns the data column identifier of the cell at position x.
1304
1305 The tree column has ID #0."""
1306 return self.identify("column", x, 0)
1307
1308
1309 def identify_region(self, x, y):
1310 """Returns one of:
1311
1312 heading: Tree heading area.
1313 separator: Space between two columns headings;
1314 tree: The tree area.
1315 cell: A data cell.
1316
1317 * Availability: Tk 8.6"""
1318 return self.identify("region", x, y)
1319
1320
1321 def identify_element(self, x, y):
1322 """Returns the element at position x, y.
1323
1324 * Availability: Tk 8.6"""
1325 return self.identify("element", x, y)
1326
1327
1328 def index(self, item):
1329 """Returns the integer index of item within its parent's list
1330 of children."""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +02001331 return self.tk.getint(self.tk.call(self._w, "index", item))
Guilherme Polocda93aa2009-01-28 13:09:03 +00001332
1333
1334 def insert(self, parent, index, iid=None, **kw):
1335 """Creates a new item and return the item identifier of the newly
1336 created item.
1337
1338 parent is the item ID of the parent item, or the empty string
1339 to create a new top-level item. index is an integer, or the value
1340 end, specifying where in the list of parent's children to insert
1341 the new item. If index is less than or equal to zero, the new node
1342 is inserted at the beginning, if index is greater than or equal to
1343 the current number of children, it is inserted at the end. If iid
1344 is specified, it is used as the item identifier, iid must not
1345 already exist in the tree. Otherwise, a new unique identifier
1346 is generated."""
1347 opts = _format_optdict(kw)
1348 if iid:
1349 res = self.tk.call(self._w, "insert", parent, index,
1350 "-id", iid, *opts)
1351 else:
1352 res = self.tk.call(self._w, "insert", parent, index, *opts)
1353
1354 return res
1355
1356
1357 def item(self, item, option=None, **kw):
1358 """Query or modify the options for the specified item.
1359
1360 If no options are given, a dict with options/values for the item
1361 is returned. If option is specified then the value for that option
1362 is returned. Otherwise, sets the options to the corresponding
1363 values as given by kw."""
1364 if option is not None:
1365 kw[option] = None
1366 return _val_or_dict(kw, self.tk.call, self._w, "item", item)
1367
1368
1369 def move(self, item, parent, index):
1370 """Moves item to position index in parent's list of children.
1371
1372 It is illegal to move an item under one of its descendants. If
1373 index is less than or equal to zero, item is moved to the
1374 beginning, if greater than or equal to the number of children,
1375 it is moved to the end. If item was detached it is reattached."""
1376 self.tk.call(self._w, "move", item, parent, index)
1377
1378 reattach = move # A sensible method name for reattaching detached items
1379
1380
1381 def next(self, item):
1382 """Returns the identifier of item's next sibling, or '' if item
1383 is the last child of its parent."""
1384 return self.tk.call(self._w, "next", item)
1385
1386
1387 def parent(self, item):
1388 """Returns the ID of the parent of item, or '' if item is at the
1389 top level of the hierarchy."""
1390 return self.tk.call(self._w, "parent", item)
1391
1392
1393 def prev(self, item):
1394 """Returns the identifier of item's previous sibling, or '' if
1395 item is the first child of its parent."""
1396 return self.tk.call(self._w, "prev", item)
1397
1398
1399 def see(self, item):
1400 """Ensure that item is visible.
1401
1402 Sets all of item's ancestors open option to True, and scrolls
1403 the widget if necessary so that item is within the visible
1404 portion of the tree."""
1405 self.tk.call(self._w, "see", item)
1406
1407
1408 def selection(self, selop=None, items=None):
1409 """If selop is not specified, returns selected items."""
1410 return self.tk.call(self._w, "selection", selop, items)
1411
1412
1413 def selection_set(self, items):
1414 """items becomes the new selection."""
1415 self.selection("set", items)
1416
1417
1418 def selection_add(self, items):
1419 """Add items to the selection."""
1420 self.selection("add", items)
1421
1422
1423 def selection_remove(self, items):
1424 """Remove items from the selection."""
1425 self.selection("remove", items)
1426
1427
1428 def selection_toggle(self, items):
1429 """Toggle the selection state of each item in items."""
1430 self.selection("toggle", items)
1431
1432
1433 def set(self, item, column=None, value=None):
1434 """With one argument, returns a dictionary of column/value pairs
1435 for the specified item. With two arguments, returns the current
1436 value of the specified column. With three arguments, sets the
1437 value of given column in given item to the specified value."""
1438 res = self.tk.call(self._w, "set", item, column, value)
1439 if column is None and value is None:
Serhiy Storchaka9be238d2014-01-07 19:32:58 +02001440 return _dict_from_tcltuple(self.tk.splitlist(res), False)
Guilherme Polocda93aa2009-01-28 13:09:03 +00001441 else:
1442 return res
1443
1444
1445 def tag_bind(self, tagname, sequence=None, callback=None):
1446 """Bind a callback for the given event sequence to the tag tagname.
1447 When an event is delivered to an item, the callbacks for each
1448 of the item's tags option are called."""
1449 self._bind((self._w, "tag", "bind", tagname), sequence, callback, add=0)
1450
1451
1452 def tag_configure(self, tagname, option=None, **kw):
1453 """Query or modify the options for the specified tagname.
1454
1455 If kw is not given, returns a dict of the option settings for tagname.
1456 If option is specified, returns the value for that option for the
1457 specified tagname. Otherwise, sets the options to the corresponding
1458 values for the given tagname."""
1459 if option is not None:
1460 kw[option] = None
1461 return _val_or_dict(kw, self.tk.call, self._w, "tag", "configure",
1462 tagname)
1463
1464
1465 def tag_has(self, tagname, item=None):
1466 """If item is specified, returns 1 or 0 depending on whether the
1467 specified item has the given tagname. Otherwise, returns a list of
1468 all items which have the specified tag.
1469
1470 * Availability: Tk 8.6"""
Serhiy Storchaka9be238d2014-01-07 19:32:58 +02001471 return self.tk.getboolean(
1472 self.tk.call(self._w, "tag", "has", tagname, item))
Guilherme Polocda93aa2009-01-28 13:09:03 +00001473
1474
Guilherme Polocda93aa2009-01-28 13:09:03 +00001475# Extensions
1476
1477class LabeledScale(Frame, object):
1478 """A Ttk Scale widget with a Ttk Label widget indicating its
1479 current value.
1480
1481 The Ttk Scale can be accessed through instance.scale, and Ttk Label
1482 can be accessed through instance.label"""
1483
1484 def __init__(self, master=None, variable=None, from_=0, to=10, **kw):
1485 """Construct an horizontal LabeledScale with parent master, a
1486 variable to be associated with the Ttk Scale widget and its range.
1487 If variable is not specified, a Tkinter.IntVar is created.
1488
1489 WIDGET-SPECIFIC OPTIONS
1490
1491 compound: 'top' or 'bottom'
1492 Specifies how to display the label relative to the scale.
1493 Defaults to 'top'.
1494 """
1495 self._label_top = kw.pop('compound', 'top') == 'top'
1496
1497 Frame.__init__(self, master, **kw)
1498 self._variable = variable or Tkinter.IntVar(master)
1499 self._variable.set(from_)
1500 self._last_valid = from_
1501
1502 self.label = Label(self)
1503 self.scale = Scale(self, variable=self._variable, from_=from_, to=to)
1504 self.scale.bind('<<RangeChanged>>', self._adjust)
1505
1506 # position scale and label according to the compound option
1507 scale_side = 'bottom' if self._label_top else 'top'
1508 label_side = 'top' if scale_side == 'bottom' else 'bottom'
1509 self.scale.pack(side=scale_side, fill='x')
1510 tmp = Label(self).pack(side=label_side) # place holder
1511 self.label.place(anchor='n' if label_side == 'top' else 's')
1512
1513 # update the label as scale or variable changes
1514 self.__tracecb = self._variable.trace_variable('w', self._adjust)
1515 self.bind('<Configure>', self._adjust)
1516 self.bind('<Map>', self._adjust)
1517
1518
1519 def destroy(self):
1520 """Destroy this widget and possibly its associated variable."""
1521 try:
1522 self._variable.trace_vdelete('w', self.__tracecb)
1523 except AttributeError:
1524 # widget has been destroyed already
1525 pass
1526 else:
1527 del self._variable
1528 Frame.destroy(self)
1529
1530
1531 def _adjust(self, *args):
1532 """Adjust the label position according to the scale."""
1533 def adjust_label():
1534 self.update_idletasks() # "force" scale redraw
1535
1536 x, y = self.scale.coords()
1537 if self._label_top:
1538 y = self.scale.winfo_y() - self.label.winfo_reqheight()
1539 else:
1540 y = self.scale.winfo_reqheight() + self.label.winfo_reqheight()
1541
1542 self.label.place_configure(x=x, y=y)
1543
Serhiy Storchaka9be238d2014-01-07 19:32:58 +02001544 from_ = _to_number(self.scale['from'])
1545 to = _to_number(self.scale['to'])
Guilherme Polocda93aa2009-01-28 13:09:03 +00001546 if to < from_:
1547 from_, to = to, from_
1548 newval = self._variable.get()
1549 if not from_ <= newval <= to:
1550 # value outside range, set value back to the last valid one
1551 self.value = self._last_valid
1552 return
1553
1554 self._last_valid = newval
1555 self.label['text'] = newval
1556 self.after_idle(adjust_label)
1557
1558
1559 def _get_value(self):
1560 """Return current scale value."""
1561 return self._variable.get()
1562
1563
1564 def _set_value(self, val):
1565 """Set new scale value."""
1566 self._variable.set(val)
1567
1568
1569 value = property(_get_value, _set_value)
1570
1571
1572class OptionMenu(Menubutton):
1573 """Themed OptionMenu, based after Tkinter's OptionMenu, which allows
1574 the user to select a value from a menu."""
1575
1576 def __init__(self, master, variable, default=None, *values, **kwargs):
1577 """Construct a themed OptionMenu widget with master as the parent,
1578 the resource textvariable set to variable, the initially selected
1579 value specified by the default parameter, the menu values given by
1580 *values and additional keywords.
1581
1582 WIDGET-SPECIFIC OPTIONS
1583
1584 style: stylename
1585 Menubutton style.
1586 direction: 'above', 'below', 'left', 'right', or 'flush'
1587 Menubutton direction.
1588 command: callback
1589 A callback that will be invoked after selecting an item.
1590 """
1591 kw = {'textvariable': variable, 'style': kwargs.pop('style', None),
1592 'direction': kwargs.pop('direction', None)}
1593 Menubutton.__init__(self, master, **kw)
1594 self['menu'] = Tkinter.Menu(self, tearoff=False)
1595
1596 self._variable = variable
1597 self._callback = kwargs.pop('command', None)
1598 if kwargs:
1599 raise Tkinter.TclError('unknown option -%s' % (
1600 kwargs.iterkeys().next()))
1601
1602 self.set_menu(default, *values)
1603
1604
1605 def __getitem__(self, item):
1606 if item == 'menu':
1607 return self.nametowidget(Menubutton.__getitem__(self, item))
1608
1609 return Menubutton.__getitem__(self, item)
1610
1611
1612 def set_menu(self, default=None, *values):
1613 """Build a new menu of radiobuttons with *values and optionally
1614 a default value."""
1615 menu = self['menu']
1616 menu.delete(0, 'end')
1617 for val in values:
1618 menu.add_radiobutton(label=val,
1619 command=Tkinter._setit(self._variable, val, self._callback))
1620
1621 if default:
1622 self._variable.set(default)
1623
1624
1625 def destroy(self):
1626 """Destroy this widget and its associated variable."""
1627 del self._variable
1628 Menubutton.destroy(self)