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