``(columns, rows)`` tuple.
:meth:`size` is an alias of :meth:`!grid_size`,
- except on the :class:`Listbox` widget,
- which provides its own :meth:`!size` method.
+ except on :class:`Listbox` and
+ :class:`ttk.Treeview <tkinter.ttk.Treeview>`,
+ which provide their own :meth:`!size` method.
.. method:: grid_slaves(row=None, column=None)
Same as :meth:`Misc.grid_size`: return a ``(columns, rows)`` tuple giving
the size of the grid.
:meth:`size` is an alias of :meth:`!grid_size`,
- except on the :class:`Listbox` widget,
- which provides its own :meth:`!size` method.
+ except on :class:`Listbox` and
+ :class:`ttk.Treeview <tkinter.ttk.Treeview>`,
+ which provide their own :meth:`!size` method.
.. method:: propagate()
propagate(flag)
.. method:: next(item)
- Returns the identifier of *item*'s next sibling, or '' if *item* is the
- last child of its parent.
+ Returns the identifier of *item*'s next sibling,
+ or '' if *item* is the last child of its parent.
+ Equivalent to ``after_item(item, hidden=True, recurse=False)``.
.. method:: parent(item)
.. method:: prev(item)
- Returns the identifier of *item*'s previous sibling, or '' if *item* is
- the first child of its parent.
+ Returns the identifier of *item*'s previous sibling,
+ or '' if *item* is the first child of its parent.
+ Equivalent to ``before_item(item, hidden=True, recurse=False)``.
+
+
+ .. method:: after_item(item, *, hidden=False, recurse=True)
+
+ Returns the identifier of the item after *item*
+ (the first child, a next sibling, or a next sibling of an ancestor),
+ or '' if there is none.
+ By default only visible items are considered;
+ if *hidden* is true, hidden items are included too.
+ If *recurse* is false, only siblings of *item* are considered
+ (see :meth:`next`).
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: before_item(item, *, hidden=False, recurse=True)
+
+ Returns the identifier of the item before *item*
+ (a previous sibling or the parent of *item*),
+ or '' if there is none.
+ By default only visible items are considered;
+ if *hidden* is true, hidden items are included too.
+ If *recurse* is false, only siblings of *item* are considered
+ (see :meth:`prev`).
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: depth(item)
+
+ Returns the number of levels between *item* and the root item.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: haschildren(item)
+
+ Returns ``True`` if *item* has children, ``False`` otherwise.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: visible(item)
+
+ Returns ``True`` if *item* is visible, ``False`` otherwise.
+ An item is visible if it is not detached, not hidden,
+ and all of its ancestors are open and not hidden.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: size(item, *, hidden=False, recurse=False)
+
+ Returns the number of children of *item*.
+ If *hidden* is true, hidden items are included.
+ If *recurse* is true, all descendants of *item* are included.
+ Use ``''`` for the root item.
+ ``size(item, hidden=True)`` equals ``len(get_children(item))``
+ (which always includes hidden items).
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: range(first, last, *, hidden=False, recurse=True)
+
+ Returns a tuple of items from *first* through *last*, inclusive.
+ If *hidden* is true, hidden items are included.
+ If *recurse* is false, descendants and ancestors are excluded.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: identifier(item, index)
+
+ Returns the identifier of the item at *index*
+ within *item*'s list of children.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: current()
+
+ Returns the current item id and column id as a 2-tuple,
+ or an empty tuple if there is none.
+ The current item is the item under the mouse pointer.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: expand(*items, recurse=False)
+
+ Set all of the specified items to the open state.
+ If *recurse* is true, also open all of their descendants;
+ this requires Tk 9.1.
+ Use ``''`` for the root item.
+ ``expand(item)`` is equivalent to ``item(item, open=True)``.
+
+ .. versionadded:: next
+
+
+ .. method:: collapse(*items, recurse=False)
+
+ Set all of the specified items to the closed state.
+ If *recurse* is true, also close all of their descendants;
+ this requires Tk 9.1.
+ Use ``''`` for the root item.
+ ``collapse(item)`` is equivalent to ``item(item, open=False)``.
+
+ .. versionadded:: next
+
+
+ .. method:: hide(*items, recurse=False)
+
+ Hide all of the specified items and all of their child items.
+ If *recurse* is true, also hide all of their descendants.
+ Use ``''`` for the root item.
+ ``hide(item)`` is equivalent to ``item(item, hidden=True)``.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: unhide(*items, recurse=False)
+
+ Unhide all of the specified items.
+ If *recurse* is true, also unhide all of their descendants.
+ Use ``''`` for the root item.
+ ``unhide(item)`` is equivalent to ``item(item, hidden=False)``.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: detached(item=None)
+
+ Returns information about detached items
+ (see :meth:`detach`).
+ Without arguments, returns a tuple of all detached items,
+ but not their descendants (see :meth:`detached_all`).
+ With *item*, returns whether *item* is detached; since Tk 9.1, also
+ returns true if an ancestor of *item* is detached.
+
+ Requires Tk 9.0 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: detached_all()
+
+ Returns a tuple of all detached items and all of their descendants
+ (see :meth:`detach`).
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellfocus(cell=None)
+
+ Get or set the focus cell.
+ Without *cell*, returns the focus cell as an ``(item, column)`` 2-tuple,
+ or an empty tuple if there is none.
+ With *cell*, sets the focus cell; use ``''`` to clear it.
+ A cell is specified as an ``(item, column)`` pair.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: sort(parent, *, column=None, command=None, dictionary=False, integer=False, real=False, nocase=False, decreasing=False, ignoreempty=False, recurse=False)
+
+ Sort the children of *parent*.
+ By default the children are sorted by the value of the first display
+ column, as Unicode strings, in increasing order.
+ *column* selects the column to sort on.
+ *dictionary*, *integer* and *real* select the comparison type;
+ *nocase* makes string comparison case-insensitive.
+ *command* is a function of two values
+ returning a negative, zero or positive number.
+ *decreasing* reverses the order.
+ *ignoreempty* skips empty values (with *integer* or *real*).
+ *recurse* also sorts all descendants.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: search(parent, pattern, *, columns=None, start=None, stop=None, dictionary=False, integer=False, real=False, nocase=False, glob=False, regexp=False, backwards=False, hidden=False, recurse=False, wraparound=False)
+
+ Search *parent*'s children for *pattern*
+ and return the identifier of the first matching item,
+ or ``''`` if there is no match.
+ By default *pattern* is matched for exact equality
+ against the value of each displayed column, as Unicode strings,
+ searching forwards through the direct children of *parent*.
+ *glob* or *regexp* select glob-style or regular expression matching;
+ *dictionary*, *integer* and *real* select the comparison type;
+ *nocase* makes it case-insensitive.
+ *columns* limits the search to the given columns.
+ *start* and *stop* bound the search;
+ *backwards* reverses its direction;
+ *wraparound* continues from the other end.
+ *hidden* also searches hidden and closed items;
+ *recurse* searches all descendants.
+
+ See :meth:`search_all`, :meth:`search_cell` and :meth:`search_all_cells`.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: search_all(parent, pattern, **kwargs)
+
+ Like :meth:`search`,
+ but returns a tuple of the identifiers of all matching items.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: search_cell(parent, pattern, **kwargs)
+
+ Like :meth:`search`,
+ but returns the first matching cell as an ``(item, column)`` 2-tuple,
+ or an empty tuple if there is no match.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: search_all_cells(parent, pattern, **kwargs)
+
+ Like :meth:`search`,
+ but returns a tuple of all matching cells,
+ each an ``(item, column)`` 2-tuple.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection()
+
+ Returns a tuple of the selected cells, each an ``(item, column)``
+ 2-tuple.
+ The cell selection is independent from the item selection
+ (see :meth:`selection`).
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_set(*cells)
+
+ The specified cells become the new cell selection.
+ Each cell is an ``(item, column)`` pair.
+ Call without arguments to clear the cell selection.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_add(*cells)
+
+ Add the specified cells to the cell selection.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_remove(*cells)
+
+ Remove the specified cells from the cell selection.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_set_range(first, last, *, hidden=True, recurse=True)
+
+ Set the cell selection to the rectangle of cells from *first* to *last*.
+ *first* and *last* are the opposite corner cells,
+ each an ``(item, column)`` pair, and must be in displayed columns.
+ All other cells are unselected.
+ If *hidden* is false, hidden cells are excluded;
+ if *recurse* is false, cells in descendant items are excluded.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_add_range(first, last, *, hidden=True, recurse=True)
+
+ Like :meth:`cellselection_set_range`,
+ but adds the rectangle of cells to the cell selection
+ instead of replacing it.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_remove_range(first, last, *, hidden=True, recurse=True)
+
+ Like :meth:`cellselection_set_range`,
+ but removes the rectangle of cells from the cell selection.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_anchor(cell=None)
+
+ Get or set the cell selection anchor.
+ Without *cell*, returns the anchor as an ``(item, column)`` 2-tuple,
+ or an empty tuple if it is unset.
+ With *cell*, sets the anchor; use ``''`` to unset it.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_includes(*cells)
+
+ Returns whether all of the specified cells are selected.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: cellselection_present()
+
+ Returns whether any cell is selected.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: tag_cell_add(tagname, *cells)
+
+ Add the given tag to each of the specified cells.
+ Each cell is an ``(item, column)`` pair.
+ Cell tags are independent from item tags.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: tag_cell_remove(tagname, *cells)
+
+ Remove the given tag from each of the specified cells.
+ If no cell is specified, the tag is removed from all cells.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
+
+
+ .. method:: tag_cell_has(tagname, cell=None)
+
+ Test for a cell tag, or list the cells that have it.
+ If *cell* is specified, returns whether that cell has the given tag.
+ Otherwise returns a tuple of all cells (as ``(item, column)`` 2-tuples)
+ that have the tag.
+
+ Requires Tk 9.1 or newer.
+
+ .. versionadded:: next
.. method:: see(item)
tkinter
-------
+* Added many :class:`tkinter.ttk.Treeview` methods wrapping the enhanced
+ ``ttk::treeview`` widget commands from Tk 9.1, such as
+ :meth:`~tkinter.ttk.Treeview.sort`, :meth:`~tkinter.ttk.Treeview.search`,
+ :meth:`~tkinter.ttk.Treeview.expand`, :meth:`~tkinter.ttk.Treeview.collapse`,
+ :meth:`~tkinter.ttk.Treeview.hide`, :meth:`~tkinter.ttk.Treeview.unhide`, and
+ methods for cell focus, selection and tagging. The
+ :meth:`~tkinter.ttk.Treeview.expand` and :meth:`~tkinter.ttk.Treeview.collapse`
+ methods (without recursion) also work on Tk older than 9.1.
+ (Contributed by Serhiy Storchaka in :gh:`151910`.)
+
* Added new :class:`!tkinter.Text` methods :meth:`~tkinter.Text.edit_canundo`
and :meth:`~tkinter.Text.edit_canredo` which return whether an undo or redo
is possible.
badge) and :meth:`~tkinter.Wm.wm_stackorder` (toplevel stacking order).
(Contributed by Serhiy Storchaka in :gh:`151874`.)
-
xml
---
self.assertEqual(self.tv.tag_has('tag2'), (item2,))
self.assertEqual(self.tv.tag_has('tag3'), ())
+ def build_tree(self):
+ # a -> a1, a2 -> a2x; b
+ tv = self.tv
+ tv.insert('', 'end', 'a')
+ tv.insert('a', 'end', 'a1')
+ tv.insert('a', 'end', 'a2')
+ tv.insert('a2', 'end', 'a2x')
+ tv.insert('', 'end', 'b')
+ return tv
+
+ @requires_tk(9, 1)
+ def test_depth(self):
+ tv = self.build_tree()
+ self.assertEqual(tv.depth('a'), 1)
+ self.assertEqual(tv.depth('a2'), 2)
+ self.assertEqual(tv.depth('a2x'), 3)
+
+ @requires_tk(9, 1)
+ def test_haschildren(self):
+ tv = self.build_tree()
+ self.assertTrue(tv.haschildren('a'))
+ self.assertTrue(tv.haschildren('a2'))
+ self.assertFalse(tv.haschildren('a1'))
+ self.assertFalse(tv.haschildren('b'))
+
+ @requires_tk(9, 1)
+ def test_identifier(self):
+ tv = self.build_tree()
+ self.assertEqual(tv.identifier('a', 0), 'a1')
+ self.assertEqual(tv.identifier('a', 1), 'a2')
+ self.assertEqual(tv.identifier('', 0), 'a')
+ self.assertEqual(tv.identifier('', 1), 'b')
+
+ @requires_tk(9, 1)
+ def test_size(self):
+ tv = self.build_tree()
+ self.assertEqual(tv.size(''), 2)
+ self.assertEqual(tv.size('a'), 2)
+ self.assertEqual(tv.size('a', recurse=True), 3)
+ self.assertEqual(tv.size('b'), 0)
+ tv.hide('a1')
+ self.assertEqual(tv.size('a'), 1)
+ self.assertEqual(tv.size('a', hidden=True), 2)
+
+ @requires_tk(9, 1)
+ def test_range(self):
+ tv = self.build_tree()
+ tv.expand('a', recurse=True)
+ self.assertEqual(tv.range('a', 'b'), ('a', 'a1', 'a2', 'a2x', 'b'))
+ self.assertEqual(tv.range('a1', 'a2'), ('a1', 'a2'))
+ self.assertEqual(tv.range('a', 'a'), ('a',))
+ tv.hide('a1')
+ self.assertEqual(tv.range('a', 'b'), ('a', 'a2', 'a2x', 'b'))
+ self.assertEqual(tv.range('a', 'b', hidden=True),
+ ('a', 'a1', 'a2', 'a2x', 'b'))
+
+ @requires_tk(9, 1)
+ def test_after_before_item(self):
+ tv = self.build_tree()
+ tv.expand('a', recurse=True)
+ self.assertEqual(tv.after_item('a'), 'a1')
+ self.assertEqual(tv.after_item('a1'), 'a2')
+ self.assertEqual(tv.after_item('a2x'), 'b')
+ self.assertEqual(tv.after_item('b'), '')
+ self.assertEqual(tv.before_item('b'), 'a2x')
+ self.assertEqual(tv.before_item('a1'), 'a')
+ self.assertEqual(tv.before_item('a'), '')
+ # With recurse=False the search stays at the sibling level.
+ self.assertEqual(tv.after_item('a', recurse=False), 'b')
+ self.assertEqual(tv.before_item('b', recurse=False), 'a')
+ # next/prev == after_item/before_item with hidden=True, recurse=False.
+ self.assertEqual(tv.after_item('a', hidden=True, recurse=False),
+ tv.next('a'))
+ self.assertEqual(tv.before_item('b', hidden=True, recurse=False),
+ tv.prev('b'))
+
+ def test_expand_collapse(self):
+ # Without recurse this works on all Tk versions (emulated before 9.1).
+ tv = self.build_tree()
+ tv.expand('a')
+ self.assertTrue(tv.item('a', 'open'))
+ self.assertFalse(tv.item('a2', 'open'))
+ tv.collapse('a')
+ self.assertFalse(tv.item('a', 'open'))
+ # Several items at once, as separate arguments or as a list.
+ tv.expand('a', 'a2')
+ self.assertTrue(tv.item('a', 'open'))
+ self.assertTrue(tv.item('a2', 'open'))
+ tv.collapse(['a', 'a2'])
+ self.assertFalse(tv.item('a', 'open'))
+ self.assertFalse(tv.item('a2', 'open'))
+
+ @requires_tk(9, 1)
+ def test_expand_collapse_recurse(self):
+ tv = self.build_tree()
+ tv.expand('a', recurse=True)
+ self.assertTrue(tv.item('a', 'open'))
+ self.assertTrue(tv.item('a2', 'open'))
+ tv.collapse('a', recurse=True)
+ self.assertFalse(tv.item('a', 'open'))
+ self.assertFalse(tv.item('a2', 'open'))
+
+ @requires_tk(9, 1)
+ def test_hide_unhide(self):
+ tv = self.build_tree()
+ tv.expand('a', recurse=True)
+ tv.hide('a1')
+ self.assertEqual(tv.range('a', 'b'), ('a', 'a2', 'a2x', 'b'))
+ tv.unhide('a1')
+ self.assertEqual(tv.range('a', 'b'), ('a', 'a1', 'a2', 'a2x', 'b'))
+ tv.hide('a1', 'a2')
+ self.assertEqual(tv.range('a', 'b'), ('a', 'b'))
+ tv.unhide(['a1', 'a2'])
+ self.assertEqual(tv.range('a', 'b'), ('a', 'a1', 'a2', 'a2x', 'b'))
+
+ @requires_tk(9, 1)
+ def test_visible(self):
+ tv = self.build_tree()
+ tv.pack()
+ self.addCleanup(tv.pack_forget)
+ self.root.update_idletasks()
+ self.assertTrue(tv.visible('a'))
+ self.assertFalse(tv.visible('a2x')) # ancestors are closed
+ tv.expand('a', recurse=True)
+ self.root.update_idletasks()
+ self.assertTrue(tv.visible('a2x'))
+ tv.hide('a2')
+ self.root.update_idletasks()
+ self.assertFalse(tv.visible('a2x')) # an ancestor is hidden
+
+ @requires_tk(9, 1)
+ def test_current(self):
+ tv = self.build_tree()
+ # No item is under the mouse pointer during the test.
+ self.assertEqual(tv.current(), ())
+
+ @requires_tk(9, 0)
+ def test_detached(self):
+ tv = self.build_tree()
+ self.assertEqual(tv.detached(), ())
+ self.assertFalse(tv.detached('a'))
+ tv.detach('a')
+ self.assertEqual(tv.detached(), ('a',)) # not the descendants
+ self.assertTrue(tv.detached('a'))
+ self.assertFalse(tv.detached('b'))
+ tv.move('a', '', 'end') # reattach
+ self.assertEqual(tv.detached(), ())
+
+ @requires_tk(9, 1)
+ def test_detached_all(self):
+ # The -all form and the ancestor-aware item query require Tk 9.1.
+ tv = self.build_tree()
+ self.assertEqual(tv.detached_all(), ())
+ tv.detach('a')
+ self.assertEqual(set(tv.detached_all()),
+ {'a', 'a1', 'a2', 'a2x'}) # with descendants
+ self.assertEqual(tv.detached(), ('a',)) # without descendants
+ self.assertTrue(tv.detached('a2x')) # an ancestor is detached
+
+ @requires_tk(9, 1)
+ def test_cellfocus(self):
+ tv = self.create(columns=('x',))
+ tv.insert('', 'end', 'a', values=('1',))
+ self.assertEqual(tv.cellfocus(), ())
+ tv.cellfocus(('a', 'x'))
+ self.assertEqual(tv.cellfocus(), ('a', 'x'))
+ tv.cellfocus('')
+ self.assertEqual(tv.cellfocus(), ())
+
+ @requires_tk(9, 1)
+ def test_sort(self):
+ tv = self.create(columns=('x',))
+ for name, value in [('c', '3'), ('a', '1'), ('b', '2')]:
+ tv.insert('', 'end', name, values=(value,))
+ tv.sort('', column='x', integer=True)
+ self.assertEqual(tv.get_children(), ('a', 'b', 'c'))
+ tv.sort('', column='x', integer=True, decreasing=True)
+ self.assertEqual(tv.get_children(), ('c', 'b', 'a'))
+ tv.sort('', column='x', command=lambda p, q: (p > q) - (p < q))
+ self.assertEqual(tv.get_children(), ('a', 'b', 'c'))
+
+ @requires_tk(9, 1)
+ def test_search(self):
+ tv = self.create(columns=('x',))
+ for name, value in [('a', '1'), ('b', '2'), ('c', '2')]:
+ tv.insert('', 'end', name, values=(value,))
+ self.assertEqual(tv.search('', '2', columns=('x',)), 'b')
+ self.assertEqual(tv.search('', 'z', columns=('x',)), '')
+ self.assertEqual(tv.search('', '2', columns=('x',), backwards=True), 'c')
+ self.assertEqual(tv.search_all('', '2', columns=('x',)), ('b', 'c'))
+ self.assertEqual(tv.search_all('', '?', columns=('x',), glob=True),
+ ('a', 'b', 'c'))
+
+ @requires_tk(9, 1)
+ def test_search_cell(self):
+ tv = self.create(columns=('x',))
+ for name, value in [('a', '1'), ('b', '2'), ('c', '2')]:
+ tv.insert('', 'end', name, values=(value,))
+ self.assertEqual(tv.search_cell('', '2', columns=('x',)), ('b', 'x'))
+ self.assertEqual(tv.search_cell('', 'z', columns=('x',)), ())
+ self.assertEqual(tv.search_all_cells('', '2', columns=('x',)),
+ (('b', 'x'), ('c', 'x')))
+
+ @requires_tk(9, 1)
+ def test_cellselection(self):
+ tv = self.create(columns=('x', 'y'))
+ for name in 'ab':
+ tv.insert('', 'end', name, values=('1', '2'))
+ self.assertEqual(tv.cellselection(), ())
+ self.assertFalse(tv.cellselection_present())
+ tv.cellselection_set(('a', 'x'), ('b', 'y'))
+ self.assertEqual(set(tv.cellselection()), {('a', 'x'), ('b', 'y')})
+ self.assertTrue(tv.cellselection_present())
+ self.assertTrue(tv.cellselection_includes(('a', 'x')))
+ self.assertFalse(tv.cellselection_includes(('a', 'y')))
+ tv.cellselection_add(('a', 'y'))
+ tv.cellselection_remove(('b', 'y'))
+ self.assertEqual(set(tv.cellselection()), {('a', 'x'), ('a', 'y')})
+ # A single list of cells is also accepted.
+ tv.cellselection_set([('b', 'x'), ('b', 'y')])
+ self.assertEqual(set(tv.cellselection()), {('b', 'x'), ('b', 'y')})
+ tv.cellselection_set() # clear
+ self.assertEqual(tv.cellselection(), ())
+ self.assertEqual(tv.cellselection_anchor(), ())
+ tv.cellselection_anchor(('a', 'x'))
+ self.assertEqual(tv.cellselection_anchor(), ('a', 'x'))
+ tv.cellselection_anchor('')
+ self.assertEqual(tv.cellselection_anchor(), ())
+
+ @requires_tk(9, 1)
+ def test_cellselection_range(self):
+ tv = self.create(columns=('x', 'y', 'z'))
+ for name in 'abc':
+ tv.insert('', 'end', name, values=('1', '2', '3'))
+ tv.cellselection_set_range(('a', 'x'), ('b', 'y'))
+ self.assertEqual(set(tv.cellselection()),
+ {('a', 'x'), ('a', 'y'), ('b', 'x'), ('b', 'y')})
+ tv.cellselection_add_range(('c', 'z'), ('c', 'z'))
+ self.assertIn(('c', 'z'), tv.cellselection())
+ tv.cellselection_remove_range(('a', 'x'), ('b', 'x'))
+ self.assertEqual(set(tv.cellselection()),
+ {('a', 'y'), ('b', 'y'), ('c', 'z')})
+
+ @requires_tk(9, 1)
+ def test_tag_cell(self):
+ tv = self.create(columns=('x', 'y'))
+ for name in 'ab':
+ tv.insert('', 'end', name, values=('1', '2'))
+ self.assertEqual(tv.tag_cell_has('hot'), ())
+ tv.tag_cell_add('hot', ('a', 'x'), ('b', 'y'))
+ self.assertTrue(tv.tag_cell_has('hot', ('a', 'x')))
+ self.assertFalse(tv.tag_cell_has('hot', ('a', 'y')))
+ self.assertEqual(set(tv.tag_cell_has('hot')), {('a', 'x'), ('b', 'y')})
+ tv.tag_cell_remove('hot', ('a', 'x'))
+ self.assertEqual(tv.tag_cell_has('hot'), (('b', 'y'),))
+ tv.tag_cell_remove('hot') # from all cells
+ self.assertEqual(tv.tag_cell_has('hot'), ())
+
@add_configure_tests(StandardTtkOptionsTests)
class SeparatorTest(AbstractWidgetTest, unittest.TestCase):
def next(self, item):
"""Returns the identifier of item's next sibling, or '' if item
- is the last child of its parent."""
+ is the last child of its parent.
+
+ Equivalent to after_item(item, hidden=True, recurse=False)."""
return self.tk.call(self._w, "next", item)
def prev(self, item):
"""Returns the identifier of item's previous sibling, or '' if
- item is the first child of its parent."""
+ item is the first child of its parent.
+
+ Equivalent to before_item(item, hidden=True, recurse=False)."""
return self.tk.call(self._w, "prev", item)
+ def after_item(self, item, *, hidden=False, recurse=True):
+ """Return the identifier of the item after item, or '' if there is
+ none.
+
+ The result can be the first child, a next sibling, or a next sibling
+ of an ancestor. By default only visible items are considered; if
+ hidden is true, hidden items are included too. If recurse is false,
+ only siblings of item are considered (next item).
+
+ * Availability: Tk 9.1"""
+ options = []
+ if hidden:
+ options.append("-hidden")
+ if not recurse:
+ options.append("-norecurse")
+ return self.tk.call(self._w, "after", *options, item)
+
+
+ def before_item(self, item, *, hidden=False, recurse=True):
+ """Return the identifier of the item before item, or '' if there is
+ none.
+
+ The result can be the previous sibling or the parent of item. By
+ default only visible items are considered; if hidden is true, hidden
+ items are included too. If recurse is false, only siblings of item
+ are considered (previous item).
+
+ * Availability: Tk 9.1"""
+ options = []
+ if hidden:
+ options.append("-hidden")
+ if not recurse:
+ options.append("-norecurse")
+ return self.tk.call(self._w, "before", *options, item)
+
+
+ def depth(self, item):
+ """Return the number of levels between item and the root item.
+
+ * Availability: Tk 9.1"""
+ return self.tk.getint(self.tk.call(self._w, "depth", item))
+
+
+ def haschildren(self, item):
+ """Return True if item has children, False otherwise.
+
+ * Availability: Tk 9.1"""
+ return self.tk.getboolean(self.tk.call(self._w, "haschildren", item))
+
+
+ def visible(self, item):
+ """Return True if item is visible, False otherwise.
+
+ An item is visible if it is not detached, not hidden, and all of its
+ ancestors are open and not hidden.
+
+ * Availability: Tk 9.1"""
+ return self.tk.getboolean(self.tk.call(self._w, "visible", item))
+
+
+ def size(self, item, *, hidden=False, recurse=False): # overrides Misc.size
+ """Return the number of children of item.
+
+ If hidden is true, hidden items are included. If recurse is true,
+ all descendants of item are included. Use '' for the root item.
+ size(item, hidden=True) equals len(get_children(item)).
+
+ * Availability: Tk 9.1"""
+ options = []
+ if hidden:
+ options.append("-hidden")
+ if recurse:
+ options.append("-recurse")
+ return self.tk.getint(self.tk.call(self._w, "size", *options, item))
+
+
+ def range(self, first, last, *, hidden=False, recurse=True):
+ """Return a tuple of items from first through last, inclusive.
+
+ If hidden is true, hidden items are included. If recurse is false,
+ descendants and ancestors are excluded.
+
+ * Availability: Tk 9.1"""
+ options = []
+ if hidden:
+ options.append("-hidden")
+ if not recurse:
+ options.append("-norecurse")
+ return self.tk.splitlist(
+ self.tk.call(self._w, "range", *options, first, last))
+
+
+ def identifier(self, item, index):
+ """Return the identifier of the item at index within item's list of
+ children.
+
+ * Availability: Tk 9.1"""
+ return self.tk.call(self._w, "identifier", item, index)
+
+
+ def current(self):
+ """Return the current item id and column id as a 2-tuple, or an empty
+ tuple if there is none.
+
+ The current item is the item under the mouse pointer.
+
+ * Availability: Tk 9.1"""
+ return self.tk.splitlist(self.tk.call(self._w, "current"))
+
+
+ def _itemlist(self, command, items, recurse):
+ if len(items) == 1 and isinstance(items[0], (tuple, list)):
+ items = items[0]
+ options = ("-recurse",) if recurse else ()
+ self.tk.call(self._w, command, *options, items)
+
+
+ def expand(self, *items, recurse=False):
+ """Set all of the specified items to the open state.
+
+ If recurse is true, also open all of their descendants; this requires
+ Tk 9.1. Use '' for the root item.
+
+ expand(item) is equivalent to item(item, open=True)."""
+ try:
+ self._itemlist("expand", items, recurse)
+ except tkinter.TclError:
+ if recurse or self.info_patchlevel() >= (9, 1):
+ raise
+ self._open(True, items)
+
+
+ def collapse(self, *items, recurse=False):
+ """Set all of the specified items to the closed state.
+
+ If recurse is true, also close all of their descendants; this requires
+ Tk 9.1. Use '' for the root item.
+
+ collapse(item) is equivalent to item(item, open=False)."""
+ try:
+ self._itemlist("collapse", items, recurse)
+ except tkinter.TclError:
+ if recurse or self.info_patchlevel() >= (9, 1):
+ raise
+ self._open(False, items)
+
+
+ def _open(self, opening, items):
+ if len(items) == 1 and isinstance(items[0], (tuple, list)):
+ items = items[0]
+ for item in items:
+ if item != '': # the root item has no open state
+ self.item(item, open=opening)
+
+
+ def hide(self, *items, recurse=False):
+ """Hide all of the specified items and all of their child items.
+
+ If recurse is true, also hide all of their descendants. Use '' for
+ the root item. hide(item) is equivalent to item(item, hidden=True).
+
+ * Availability: Tk 9.1"""
+ self._itemlist("hide", items, recurse)
+
+
+ def unhide(self, *items, recurse=False):
+ """Unhide all of the specified items.
+
+ If recurse is true, also unhide all of their descendants. Use '' for
+ the root item. unhide(item) is equivalent to item(item, hidden=False).
+
+ * Availability: Tk 9.1"""
+ self._itemlist("unhide", items, recurse)
+
+
+ def detached(self, item=None):
+ """Return all detached items, or whether item is detached.
+
+ Without arguments, return a tuple of all detached items (but not
+ their descendants; see detached_all). With item, return whether item
+ is detached; since Tk 9.1, also return true if an ancestor of item
+ is detached.
+
+ * Availability: Tk 9.0"""
+ if item is None:
+ return self.tk.splitlist(self.tk.call(self._w, "detached"))
+ return self.tk.getboolean(self.tk.call(self._w, "detached", item))
+
+
+ def detached_all(self):
+ """Return a tuple of all detached items and all of their descendants.
+
+ * Availability: Tk 9.1"""
+ return self.tk.splitlist(self.tk.call(self._w, "detached", "-all"))
+
+
+ def cellfocus(self, cell=None):
+ """Get or set the focus cell.
+
+ Without cell, return the focus cell as an (item, column) 2-tuple, or
+ an empty tuple if there is none. With cell, set the focus cell; use
+ '' to clear it. A cell is specified as an (item, column) pair.
+
+ * Availability: Tk 9.1"""
+ if cell is None:
+ return self.tk.splitlist(self.tk.call(self._w, "cellfocus"))
+ return self.tk.call(self._w, "cellfocus", cell)
+
+
+ def sort(self, parent, *, column=None, command=None, dictionary=False,
+ integer=False, real=False, nocase=False, decreasing=False,
+ ignoreempty=False, recurse=False):
+ """Sort the children of parent.
+
+ By default the children are sorted by the value of the first display
+ column, as Unicode strings, in increasing order. column selects the
+ column to sort on. dictionary, integer and real select the
+ comparison type; nocase makes string comparison case-insensitive.
+ command is a function of two values returning a negative, zero or
+ positive number. decreasing reverses the order. ignoreempty skips
+ empty values (with integer or real). recurse also sorts all
+ descendants.
+
+ * Availability: Tk 9.1"""
+ options = []
+ if column is not None:
+ options += ("-column", column)
+ if dictionary:
+ options.append("-dictionary")
+ if integer:
+ options.append("-integer")
+ if real:
+ options.append("-real")
+ if nocase:
+ options.append("-nocase")
+ if decreasing:
+ options.append("-decreasing")
+ if ignoreempty:
+ options.append("-ignoreempty")
+ if recurse:
+ options.append("-recurse")
+ if command is None:
+ self.tk.call(self._w, "sort", parent, *options)
+ else:
+ cmd = self.register(command)
+ try:
+ self.tk.call(self._w, "sort", parent, *options,
+ "-command", cmd)
+ finally:
+ self.deletecommand(cmd)
+
+
+ def search(self, parent, pattern, *, columns=None, start=None, stop=None,
+ dictionary=False, integer=False, real=False, nocase=False,
+ glob=False, regexp=False, backwards=False, hidden=False,
+ recurse=False, wraparound=False):
+ """Search parent's children for pattern and return the first match.
+
+ By default pattern is matched for exact equality against the value of
+ each displayed column, as Unicode strings, searching forwards through
+ the direct children of parent. glob or regexp select glob-style or
+ regular expression matching; dictionary, integer and real select the
+ comparison type; nocase makes it case-insensitive. columns limits the
+ search to the given columns. start and stop bound the search;
+ backwards reverses its direction; wraparound continues from the other
+ end. hidden also searches hidden and closed items; recurse searches
+ all descendants.
+
+ Return the identifier of the first matching item, or '' if there is no
+ match. See search_all (all matching items), search_cell (the first
+ matching cell) and search_all_cells (all matching cells).
+
+ * Availability: Tk 9.1"""
+ return self._search(False, False, parent, pattern, columns, start,
+ stop, dictionary, integer, real, nocase, glob,
+ regexp, backwards, hidden, recurse, wraparound)
+
+
+ def search_all(self, parent, pattern, *, columns=None, start=None,
+ stop=None, dictionary=False, integer=False, real=False,
+ nocase=False, glob=False, regexp=False, backwards=False,
+ hidden=False, recurse=False, wraparound=False):
+ """Search parent's children for pattern and return all matches.
+
+ Like search, but returns a tuple of the identifiers of all matching
+ items.
+
+ * Availability: Tk 9.1"""
+ return self._search(True, False, parent, pattern, columns, start,
+ stop, dictionary, integer, real, nocase, glob,
+ regexp, backwards, hidden, recurse, wraparound)
+
+
+ def search_cell(self, parent, pattern, *, columns=None, start=None,
+ stop=None, dictionary=False, integer=False, real=False,
+ nocase=False, glob=False, regexp=False, backwards=False,
+ hidden=False, recurse=False, wraparound=False):
+ """Search parent's children for pattern and return the first cell.
+
+ Like search, but matches and returns a cell, as an (item, column)
+ 2-tuple, or () if there is no match.
+
+ * Availability: Tk 9.1"""
+ return self._search(False, True, parent, pattern, columns, start,
+ stop, dictionary, integer, real, nocase, glob,
+ regexp, backwards, hidden, recurse, wraparound)
+
+
+ def search_all_cells(self, parent, pattern, *, columns=None, start=None,
+ stop=None, dictionary=False, integer=False,
+ real=False, nocase=False, glob=False, regexp=False,
+ backwards=False, hidden=False, recurse=False,
+ wraparound=False):
+ """Search parent's children for pattern and return all matching cells.
+
+ Like search, but returns a tuple of all matching cells, each an
+ (item, column) 2-tuple.
+
+ * Availability: Tk 9.1"""
+ return self._search(True, True, parent, pattern, columns, start,
+ stop, dictionary, integer, real, nocase, glob,
+ regexp, backwards, hidden, recurse, wraparound)
+
+
+ def _search(self, all, cell, parent, pattern, columns, start, stop,
+ dictionary, integer, real, nocase, glob, regexp, backwards,
+ hidden, recurse, wraparound):
+ options = []
+ if columns is not None:
+ options += ("-columns", columns)
+ if start is not None:
+ options += ("-start", start)
+ if stop is not None:
+ options += ("-stop", stop)
+ if dictionary:
+ options.append("-dictionary")
+ if integer:
+ options.append("-integer")
+ if real:
+ options.append("-real")
+ if nocase:
+ options.append("-nocase")
+ if glob:
+ options.append("-glob")
+ if regexp:
+ options.append("-regexp")
+ if backwards:
+ options.append("-backwards")
+ if hidden:
+ options.append("-hidden")
+ if recurse:
+ options.append("-recurse")
+ if wraparound:
+ options.append("-wraparound")
+ if cell:
+ options.append("-cell")
+ if all:
+ options.append("-all")
+ res = self.tk.call(self._w, "search", parent, *options, pattern)
+ if cell:
+ cells = tuple(self.tk.splitlist(c)
+ for c in self.tk.splitlist(res))
+ if all:
+ return cells
+ return cells[0] if cells else ()
+ if all:
+ return self.tk.splitlist(res)
+ return res
+
+
+ @staticmethod
+ def _cells(cells):
+ # Accept either several (item, column) cells or a single list of them.
+ if (len(cells) == 1 and cells[0]
+ and isinstance(cells[0], (tuple, list))
+ and isinstance(cells[0][0], (tuple, list))):
+ return cells[0]
+ return cells
+
+
+ def cellselection(self):
+ """Return a tuple of the selected cells.
+
+ Each cell is an (item, column) 2-tuple. The cell selection is
+ independent from the item selection (see selection).
+
+ * Availability: Tk 9.1"""
+ return tuple(self.tk.splitlist(c) for c in
+ self.tk.splitlist(self.tk.call(self._w, "cellselection")))
+
+
+ def _cellselection(self, selop, cells):
+ self.tk.call(self._w, "cellselection", selop, self._cells(cells))
+
+
+ def cellselection_set(self, *cells):
+ """The specified cells become the new cell selection.
+
+ Each cell is an (item, column) pair. Call without arguments to clear
+ the cell selection.
+
+ * Availability: Tk 9.1"""
+ self._cellselection("set", cells)
+
+
+ def cellselection_add(self, *cells):
+ """Add the specified cells to the cell selection.
+
+ * Availability: Tk 9.1"""
+ self._cellselection("add", cells)
+
+
+ def cellselection_remove(self, *cells):
+ """Remove the specified cells from the cell selection.
+
+ * Availability: Tk 9.1"""
+ self._cellselection("remove", cells)
+
+
+ def _cellselection_range(self, selop, first, last, hidden, recurse):
+ options = []
+ if not hidden:
+ options.append("-nohidden")
+ if not recurse:
+ options.append("-norecurse")
+ self.tk.call(self._w, "cellselection", selop, *options, first, last)
+
+
+ def cellselection_set_range(self, first, last, *, hidden=True,
+ recurse=True):
+ """Set the cell selection to the rectangle of cells from first to last.
+
+ first and last are the opposite corner cells, each an (item, column)
+ pair, and must be in displayed columns. All other cells are
+ unselected. If hidden is false, hidden cells are excluded; if recurse
+ is false, cells in descendant items are excluded.
+
+ * Availability: Tk 9.1"""
+ self._cellselection_range("set", first, last, hidden, recurse)
+
+
+ def cellselection_add_range(self, first, last, *, hidden=True,
+ recurse=True):
+ """Add the rectangle of cells from first to last to the cell selection.
+
+ Like cellselection_set_range, but adds to the selection instead of
+ replacing it.
+
+ * Availability: Tk 9.1"""
+ self._cellselection_range("add", first, last, hidden, recurse)
+
+
+ def cellselection_remove_range(self, first, last, *, hidden=True,
+ recurse=True):
+ """Remove the rectangle of cells from first to last from the selection.
+
+ Like cellselection_set_range, but removes the cells from the selection.
+
+ * Availability: Tk 9.1"""
+ self._cellselection_range("remove", first, last, hidden, recurse)
+
+
+ def cellselection_anchor(self, cell=None):
+ """Get or set the cell selection anchor.
+
+ Without cell, return the anchor as an (item, column) 2-tuple, or an
+ empty tuple if unset. With cell, set the anchor; use '' to unset it.
+
+ * Availability: Tk 9.1"""
+ if cell is None:
+ return self.tk.splitlist(
+ self.tk.call(self._w, "cellselection", "anchor"))
+ return self.tk.call(self._w, "cellselection", "anchor", cell)
+
+
+ def cellselection_includes(self, *cells):
+ """Return whether all of the specified cells are selected.
+
+ * Availability: Tk 9.1"""
+ return self.tk.getboolean(self.tk.call(
+ self._w, "cellselection", "includes", self._cells(cells)))
+
+
+ def cellselection_present(self):
+ """Return whether any cell is selected.
+
+ * Availability: Tk 9.1"""
+ return self.tk.getboolean(
+ self.tk.call(self._w, "cellselection", "present"))
+
+
+ def tag_cell_add(self, tagname, *cells):
+ """Add the given tag to each of the specified cells.
+
+ Each cell is an (item, column) pair. Cell tags are independent from
+ item tags (see tag_add).
+
+ * Availability: Tk 9.1"""
+ self.tk.call(self._w, "tag", "cell", "add", tagname, self._cells(cells))
+
+
+ def tag_cell_remove(self, tagname, *cells):
+ """Remove the given tag from each of the specified cells.
+
+ If no cell is specified, the tag is removed from all cells.
+
+ * Availability: Tk 9.1"""
+ if cells:
+ self.tk.call(self._w, "tag", "cell", "remove", tagname,
+ self._cells(cells))
+ else:
+ # Omit the cell list entirely (an empty list would match no cell).
+ self.tk.call(self._w, "tag", "cell", "remove", tagname)
+
+
+ def tag_cell_has(self, tagname, cell=None):
+ """Test for a cell tag, or list the cells that have it.
+
+ If cell is specified, return whether that cell has the given tag.
+ Otherwise return a tuple of all cells (as (item, column) 2-tuples)
+ that have the tag.
+
+ * Availability: Tk 9.1"""
+ if cell is None:
+ return tuple(self.tk.splitlist(c) for c in self.tk.splitlist(
+ self.tk.call(self._w, "tag", "cell", "has", tagname)))
+ return self.tk.getboolean(
+ self.tk.call(self._w, "tag", "cell", "has", tagname, cell))
+
+
def see(self, item):
"""Ensure that item is visible.
--- /dev/null
+Added :class:`tkinter.ttk.Treeview` methods wrapping the enhanced
+``ttk::treeview`` widget commands added in Tk 9.1 (and the ``detached`` query
+added in Tk 9.0): item navigation and queries, opening, hiding, sorting and
+searching of items, and cell focus, selection and tagging. The
+:meth:`~tkinter.ttk.Treeview.expand` and :meth:`~tkinter.ttk.Treeview.collapse`
+methods (without recursion) also work on Tk older than 9.1.