Commit edb6428e authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #21402: tkinter.ttk now works when default root window is not set.

parent 49b2086a
......@@ -3,6 +3,17 @@ import sys
import unittest
import ttk
class MockTkApp:
def splitlist(self, arg):
if isinstance(arg, tuple):
return arg
return arg.split(':')
def wantobjects(self):
return True
class MockTclObj(object):
typename = 'test'
......@@ -353,20 +364,22 @@ class InternalFunctionsTest(unittest.TestCase):
def test_list_from_layouttuple(self):
tk = MockTkApp()
# empty layout tuple
self.assertFalse(ttk._list_from_layouttuple(()))
self.assertFalse(ttk._list_from_layouttuple(tk, ()))
# shortest layout tuple
self.assertEqual(ttk._list_from_layouttuple(('name', )),
self.assertEqual(ttk._list_from_layouttuple(tk, ('name', )),
[('name', {})])
# not so interesting ltuple
sample_ltuple = ('name', '-option', 'value')
self.assertEqual(ttk._list_from_layouttuple(sample_ltuple),
self.assertEqual(ttk._list_from_layouttuple(tk, sample_ltuple),
[('name', {'option': 'value'})])
# empty children
self.assertEqual(ttk._list_from_layouttuple(
self.assertEqual(ttk._list_from_layouttuple(tk,
('something', '-children', ())),
[('something', {'children': []})]
)
......@@ -379,7 +392,7 @@ class InternalFunctionsTest(unittest.TestCase):
)
)
)
self.assertEqual(ttk._list_from_layouttuple(ltuple),
self.assertEqual(ttk._list_from_layouttuple(tk, ltuple),
[('name', {'option': 'niceone', 'children':
[('otherone', {'otheropt': 'othervalue', 'children':
[('child', {})]
......@@ -388,29 +401,37 @@ class InternalFunctionsTest(unittest.TestCase):
)
# bad tuples
self.assertRaises(ValueError, ttk._list_from_layouttuple,
self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('name', 'no_minus'))
self.assertRaises(ValueError, ttk._list_from_layouttuple,
self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('name', 'no_minus', 'value'))
self.assertRaises(ValueError, ttk._list_from_layouttuple,
self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('something', '-children')) # no children
import Tkinter
if not Tkinter._default_root or Tkinter._default_root.wantobjects():
self.assertRaises(ValueError, ttk._list_from_layouttuple,
('something', '-children', 'value')) # invalid children
self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('something', '-children', 'value')) # invalid children
def test_val_or_dict(self):
def func(opt, val=None):
def func(res, opt=None, val=None):
if opt is None:
return res
if val is None:
return "test val"
return (opt, val)
options = {'test': None}
self.assertEqual(ttk._val_or_dict(options, func), "test val")
tk = MockTkApp()
tk.call = func
self.assertEqual(ttk._val_or_dict(tk, {}, '-test:3'),
{'test': '3'})
self.assertEqual(ttk._val_or_dict(tk, {}, ('-test', 3)),
{'test': 3})
self.assertEqual(ttk._val_or_dict(tk, {'test': None}, 'x:y'),
'test val')
options = {'test': 3}
self.assertEqual(ttk._val_or_dict(options, func), options)
self.assertEqual(ttk._val_or_dict(tk, {'test': 3}, 'x:y'),
{'test': 3})
def test_convert_stringval(self):
......
......@@ -274,7 +274,7 @@ def _list_from_statespec(stuple):
it = iter(nval)
return [_flatten(spec) for spec in zip(it, it)]
def _list_from_layouttuple(ltuple):
def _list_from_layouttuple(tk, ltuple):
"""Construct a list from the tuple returned by ttk::layout, this is
somewhat the reverse of _format_layoutlist."""
res = []
......@@ -295,17 +295,16 @@ def _list_from_layouttuple(ltuple):
indx += 2
if opt == 'children':
if (Tkinter._default_root and
not Tkinter._default_root.wantobjects()):
val = Tkinter._default_root.splitlist(val)
val = _list_from_layouttuple(val)
if not tk.wantobjects():
val = tk.splitlist(val)
val = _list_from_layouttuple(tk, val)
opts[opt] = val
return res
def _val_or_dict(options, func, *args):
"""Format options then call func with args and options and return
def _val_or_dict(tk, options, *args):
"""Format options then call Tk command with args and options and return
the appropriate result.
If no option is specified, a dict is returned. If a option is
......@@ -313,14 +312,12 @@ def _val_or_dict(options, func, *args):
Otherwise, the function just sets the passed options and the caller
shouldn't be expecting a return value anyway."""
options = _format_optdict(options)
res = func(*(args + options))
res = tk.call(*(args + options))
if len(options) % 2: # option specified without a value, return its value
return res
if Tkinter._default_root:
res = Tkinter._default_root.splitlist(res)
return _dict_from_tcltuple(res)
return _dict_from_tcltuple(tk.splitlist(res))
def _convert_stringval(value):
"""Converts a value to, hopefully, a more appropriate Python object."""
......@@ -398,7 +395,7 @@ class Style(object):
a sequence identifying the value for that option."""
if query_opt is not None:
kw[query_opt] = None
return _val_or_dict(kw, self.tk.call, self._name, "configure", style)
return _val_or_dict(self.tk, kw, self._name, "configure", style)
def map(self, style, query_opt=None, **kw):
......@@ -468,7 +465,7 @@ class Style(object):
lspec = "null" # could be any other word, but this may make sense
# when calling layout(style) later
return _list_from_layouttuple(self.tk.splitlist(
return _list_from_layouttuple(self.tk, self.tk.splitlist(
self.tk.call(self._name, "layout", style, lspec)))
......@@ -909,7 +906,7 @@ class Notebook(Widget):
options to the corresponding values."""
if option is not None:
kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "tab", tab_id)
return _val_or_dict(self.tk, kw, self._w, "tab", tab_id)
def tabs(self):
......@@ -986,7 +983,7 @@ class Panedwindow(Widget, Tkinter.PanedWindow):
Otherwise, sets the options to the corresponding values."""
if option is not None:
kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "pane", pane)
return _val_or_dict(self.tk, kw, self._w, "pane", pane)
def sashpos(self, index, newpos=None):
......@@ -1225,7 +1222,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView):
Otherwise, sets the options to the corresponding values."""
if option is not None:
kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "column", column)
return _val_or_dict(self.tk, kw, self._w, "column", column)
def delete(self, *items):
......@@ -1284,7 +1281,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView):
if option is not None:
kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, 'heading', column)
return _val_or_dict(self.tk, kw, self._w, 'heading', column)
def identify(self, component, x, y):
......@@ -1363,7 +1360,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView):
values as given by kw."""
if option is not None:
kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "item", item)
return _val_or_dict(self.tk, kw, self._w, "item", item)
def move(self, item, parent, index):
......@@ -1458,7 +1455,7 @@ class Treeview(Widget, Tkinter.XView, Tkinter.YView):
values for the given tagname."""
if option is not None:
kw[option] = None
return _val_or_dict(kw, self.tk.call, self._w, "tag", "configure",
return _val_or_dict(self.tk, kw, self._w, "tag", "configure",
tagname)
......
......@@ -18,6 +18,8 @@ Core and Builtins
Library
-------
- Issue #21402: Tkinter.ttk now works when default root window is not set.
- Issue #10203: sqlite3.Row now truly supports sequence protocol. In particulr
it supports reverse() and negative indices. Original patch by Claudiu Popa.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment