Skip to content

Commit 575a0fe

Browse files
gh-101284: Allow passing Menubutton options to tkinter.OptionMenu
Arbitrary keyword arguments are now forwarded to the underlying Menubutton and can override OptionMenu's default appearance options. The positional API is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 3f09a17 commit 575a0fe

5 files changed

Lines changed: 39 additions & 12 deletions

File tree

Doc/library/tkinter.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4844,6 +4844,8 @@ Widget classes
48444844
is the initial choice, and *values* are the remaining menu entries.
48454845
The keyword argument *command* may be given a callback that is invoked with
48464846
the selected value, and the keyword argument *name* sets the Tk widget name.
4847+
Other keyword arguments are passed to the underlying :class:`Menubutton`
4848+
and may override its default appearance.
48474849

48484850
.. method:: destroy()
48494851

@@ -4852,6 +4854,9 @@ Widget classes
48524854
.. versionchanged:: 3.14
48534855
Added support for the *name* keyword argument.
48544856

4857+
.. versionchanged:: next
4858+
Other :class:`Menubutton` options can now be passed as keyword arguments.
4859+
48554860

48564861

48574862
.. class:: PanedWindow(master=None, cnf={}, **kw)

Doc/whatsnew/3.16.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ tkinter
216216
dithered image when its data was supplied in pieces.
217217
(Contributed by Serhiy Storchaka in :gh:`151888`.)
218218

219+
* :class:`tkinter.OptionMenu` now accepts arbitrary :class:`!tkinter.Menubutton`
220+
options as keyword arguments, which can also override its default appearance.
221+
(Contributed by Serhiy Storchaka in :gh:`101284`.)
222+
219223
xml
220224
---
221225

Lib/test/test_tkinter/test_widgets.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,22 @@ class OptionMenuTest(MenubuttonTest, unittest.TestCase):
437437
def create(self, default='b', values=('a', 'b', 'c'), **kwargs):
438438
return tkinter.OptionMenu(self.root, None, default, *values, **kwargs)
439439

440+
def test_kwargs(self):
441+
# Menubutton options can be passed at construction (gh-101284).
442+
widget = tkinter.OptionMenu(self.root, None, 'b',
443+
width=10, direction='right')
444+
self.assertEqual(int(widget['width']), 10)
445+
self.assertEqual(str(widget['direction']), 'right')
446+
# They override OptionMenu's own appearance defaults,
447+
widget = tkinter.OptionMenu(self.root, None, 'b', relief='flat')
448+
self.assertEqual(str(widget['relief']), 'flat')
449+
# which otherwise keep their historical values.
450+
widget = tkinter.OptionMenu(self.root, None, 'b')
451+
self.assertEqual(str(widget['relief']), 'raised')
452+
440453
def test_bad_kwarg(self):
441-
with self.assertRaisesRegex(TclError, r"^unknown option -image$"):
442-
tkinter.OptionMenu(self.root, None, 'b', image='')
454+
with self.assertRaisesRegex(TclError, r'^unknown option "-spam"$'):
455+
tkinter.OptionMenu(self.root, None, 'b', spam='')
443456

444457
def test_specify_name(self):
445458
widget = tkinter.OptionMenu(self.root, None, ':)', name="option_menu")

Lib/tkinter/__init__.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4516,20 +4516,23 @@ def __init__(self, master, variable, value, *values, **kwargs):
45164516
"""Construct an optionmenu widget with the parent MASTER, with
45174517
the option textvariable set to VARIABLE, the initially selected
45184518
value VALUE, the other menu values VALUES and an additional
4519-
keyword argument command."""
4520-
kw = {"borderwidth": 2, "textvariable": variable,
4521-
"indicatoron": 1, "relief": RAISED, "anchor": "c",
4522-
"highlightthickness": 2, "name": kwargs.pop("name", None)}
4519+
keyword argument command.
4520+
4521+
Other keyword arguments are passed to the underlying menubutton
4522+
and may override its default appearance."""
4523+
name = kwargs.pop("name", None)
4524+
callback = kwargs.pop("command", None)
4525+
# Default appearance, which may be overridden by keyword arguments.
4526+
kw = {"borderwidth": 2, "indicatoron": 1, "relief": RAISED,
4527+
"anchor": "c", "highlightthickness": 2}
4528+
kw.update(kwargs)
4529+
# These options are controlled by OptionMenu itself.
4530+
kw["textvariable"] = variable
4531+
kw["name"] = name
45234532
Widget.__init__(self, master, "menubutton", kw)
45244533
self.widgetName = 'tk_optionMenu'
45254534
menu = self.__menu = Menu(self, name="menu", tearoff=0)
45264535
self.menuname = menu._w
4527-
# 'command' is the only supported keyword
4528-
callback = kwargs.get('command')
4529-
if 'command' in kwargs:
4530-
del kwargs['command']
4531-
if kwargs:
4532-
raise TclError('unknown option -'+next(iter(kwargs)))
45334536
menu.add_command(label=value,
45344537
command=_setit(variable, value, callback))
45354538
for v in values:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:class:`tkinter.OptionMenu` now accepts arbitrary :class:`!tkinter.Menubutton`
2+
options as keyword arguments and uses them to override its default appearance.

0 commit comments

Comments
 (0)