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

This commit is contained in:
Serhiy Storchaka 2014-05-28 18:42:05 +03:00
commit 24604d5b4e
3 changed files with 57 additions and 36 deletions

View File

@ -1,7 +1,19 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
import unittest import unittest
import tkinter
from tkinter import ttk from tkinter 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): class MockTclObj(object):
typename = 'test' typename = 'test'
@ -352,20 +364,22 @@ class InternalFunctionsTest(unittest.TestCase):
def test_list_from_layouttuple(self): def test_list_from_layouttuple(self):
tk = MockTkApp()
# empty layout tuple # empty layout tuple
self.assertFalse(ttk._list_from_layouttuple(())) self.assertFalse(ttk._list_from_layouttuple(tk, ()))
# shortest layout tuple # shortest layout tuple
self.assertEqual(ttk._list_from_layouttuple(('name', )), self.assertEqual(ttk._list_from_layouttuple(tk, ('name', )),
[('name', {})]) [('name', {})])
# not so interesting ltuple # not so interesting ltuple
sample_ltuple = ('name', '-option', 'value') 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'})]) [('name', {'option': 'value'})])
# empty children # empty children
self.assertEqual(ttk._list_from_layouttuple( self.assertEqual(ttk._list_from_layouttuple(tk,
('something', '-children', ())), ('something', '-children', ())),
[('something', {'children': []})] [('something', {'children': []})]
) )
@ -378,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': [('name', {'option': 'niceone', 'children':
[('otherone', {'otheropt': 'othervalue', 'children': [('otherone', {'otheropt': 'othervalue', 'children':
[('child', {})] [('child', {})]
@ -387,29 +401,37 @@ class InternalFunctionsTest(unittest.TestCase):
) )
# bad tuples # bad tuples
self.assertRaises(ValueError, ttk._list_from_layouttuple, self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('name', 'no_minus')) ('name', 'no_minus'))
self.assertRaises(ValueError, ttk._list_from_layouttuple, self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('name', 'no_minus', 'value')) ('name', 'no_minus', 'value'))
self.assertRaises(ValueError, ttk._list_from_layouttuple, self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
('something', '-children')) # no children ('something', '-children')) # no children
import tkinter self.assertRaises(ValueError, ttk._list_from_layouttuple, tk,
if not tkinter._default_root or tkinter._default_root.wantobjects(): ('something', '-children', 'value')) # invalid children
self.assertRaises(ValueError, ttk._list_from_layouttuple,
('something', '-children', 'value')) # invalid children
def test_val_or_dict(self): 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: if val is None:
return "test val" return "test val"
return (opt, val) return (opt, val)
options = {'test': None} tk = MockTkApp()
self.assertEqual(ttk._val_or_dict(options, func), "test val") tk.call = func
options = {'test': 3} self.assertEqual(ttk._val_or_dict(tk, {}, '-test:3'),
self.assertEqual(ttk._val_or_dict(options, func), options) {'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')
self.assertEqual(ttk._val_or_dict(tk, {'test': 3}, 'x:y'),
{'test': 3})
def test_convert_stringval(self): def test_convert_stringval(self):

View File

@ -272,7 +272,7 @@ def _list_from_statespec(stuple):
it = iter(nval) it = iter(nval)
return [_flatten(spec) for spec in zip(it, it)] 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 """Construct a list from the tuple returned by ttk::layout, this is
somewhat the reverse of _format_layoutlist.""" somewhat the reverse of _format_layoutlist."""
res = [] res = []
@ -293,17 +293,16 @@ def _list_from_layouttuple(ltuple):
indx += 2 indx += 2
if opt == 'children': if opt == 'children':
if (tkinter._default_root and if not tk.wantobjects():
not tkinter._default_root.wantobjects()): val = tk.splitlist(val)
val = tkinter._default_root.splitlist(val) val = _list_from_layouttuple(tk, val)
val = _list_from_layouttuple(val)
opts[opt] = val opts[opt] = val
return res return res
def _val_or_dict(options, func, *args): def _val_or_dict(tk, options, *args):
"""Format options then call func with args and options and return """Format options then call Tk command with args and options and return
the appropriate result. the appropriate result.
If no option is specified, a dict is returned. If a option is If no option is specified, a dict is returned. If a option is
@ -311,14 +310,12 @@ def _val_or_dict(options, func, *args):
Otherwise, the function just sets the passed options and the caller Otherwise, the function just sets the passed options and the caller
shouldn't be expecting a return value anyway.""" shouldn't be expecting a return value anyway."""
options = _format_optdict(options) 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 if len(options) % 2: # option specified without a value, return its value
return res return res
if tkinter._default_root: return _dict_from_tcltuple(tk.splitlist(res))
res = tkinter._default_root.splitlist(res)
return _dict_from_tcltuple(res)
def _convert_stringval(value): def _convert_stringval(value):
"""Converts a value to, hopefully, a more appropriate Python object.""" """Converts a value to, hopefully, a more appropriate Python object."""
@ -396,7 +393,7 @@ class Style(object):
a sequence identifying the value for that option.""" a sequence identifying the value for that option."""
if query_opt is not None: if query_opt is not None:
kw[query_opt] = 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): def map(self, style, query_opt=None, **kw):
@ -466,7 +463,7 @@ class Style(object):
lspec = "null" # could be any other word, but this may make sense lspec = "null" # could be any other word, but this may make sense
# when calling layout(style) later # 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))) self.tk.call(self._name, "layout", style, lspec)))
@ -907,7 +904,7 @@ class Notebook(Widget):
options to the corresponding values.""" options to the corresponding values."""
if option is not None: if option is not None:
kw[option] = 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): def tabs(self):
@ -984,7 +981,7 @@ class Panedwindow(Widget, tkinter.PanedWindow):
Otherwise, sets the options to the corresponding values.""" Otherwise, sets the options to the corresponding values."""
if option is not None: if option is not None:
kw[option] = 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): def sashpos(self, index, newpos=None):
@ -1223,7 +1220,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
Otherwise, sets the options to the corresponding values.""" Otherwise, sets the options to the corresponding values."""
if option is not None: if option is not None:
kw[option] = 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): def delete(self, *items):
@ -1282,7 +1279,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
if option is not None: if option is not None:
kw[option] = 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): def identify(self, component, x, y):
@ -1361,7 +1358,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
values as given by kw.""" values as given by kw."""
if option is not None: if option is not None:
kw[option] = 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): def move(self, item, parent, index):
@ -1456,7 +1453,7 @@ class Treeview(Widget, tkinter.XView, tkinter.YView):
values for the given tagname.""" values for the given tagname."""
if option is not None: if option is not None:
kw[option] = 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) tagname)

View File

@ -89,6 +89,8 @@ Core and Builtins
Library Library
------- -------
- Issue #21402: tkinter.ttk now works when default root window is not set.
- Issue #3015: _tkinter.create() now creates tkapp object with wantobject=1 by - Issue #3015: _tkinter.create() now creates tkapp object with wantobject=1 by
default. default.