mirror of https://github.com/python/cpython
Issue #21402: tkinter.ttk now works when default root window is not set.
This commit is contained in:
commit
24604d5b4e
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue