Первый параметр tkinter optionmenu исчезает

В окне выпадающего списка появляется список виджетов ttk optionmenu со всеми его значениями. После выбора любого значения первое значение в списке исчезает, никогда не появляется снова...

Кто-нибудь знает, почему? Является ли это особенностью дизайна виджета? Попробуйте следующее:

import tkinter.ttk as ttk
import tkinter as tk

a = tk.Tk()

options = ['1', '2', '3']
value = tk.StringVar()

masterframe = ttk.Frame()
masterframe.pack()

dropdown = ttk.OptionMenu(masterframe, value, *options)
dropdown.pack()

a.mainloop()

Примечание. Другой пользователь задал тот же вопрос: OptionMenu не будет показывать первый вариант при нажатии (Tkinter)

Кажется, они нашли обходное решение, но не поняли, почему это происходит.

UPDATE: на самом деле это поведение появляется только при использовании виджета ttk. Виджет tk отлично работает (хотя выглядит очень уродливо).

Ответ 1

Подпись команды ttk.OptionMenu такова:

def __init__(self, master, variable, default=None, *values, **kwargs):

Это docstring:

"" Создайте тематический виджет OptionMenu с мастером как родительский, resource textvariable, установленный в переменную, первоначально выбранное значение заданный параметром по умолчанию, значения меню, заданные параметром * значения и дополнительные ключевые слова.

Обратите внимание на параметр default, который предшествует списку значений. Вместо добавления пустого элемента в список значений добавьте любое значение, которое вы хотите по умолчанию:

options = ['1', '2', '3']
dropdown = ttk.OptionMenu(masterframe, value, options[1], *options)

Ответ 2

просто добавляю к ответам других парней, так как они не работают для меня. Я обнаружил, что если вы не установите параметр виджета в StringVar/IntVar, он не показывает установленное стандартное значение. Это может показаться глупым, но мне потребовалось много времени, чтобы понять это. Надеюсь, это поможет, увидимся. Пример:

master = tk.Tk()
var = tk.StringVar(master)
master.mainloop()

Ответ 3

Кажется, что с ttk.OptionMenu первая запись в списке опций должна быть пуста:

import tkinter.ttk as ttk
import tkinter as tk

a = tk.Tk()

options = ['', '1', '2', '3']
value = tk.StringVar()
value.set(options[1])

masterframe = ttk.Frame()
masterframe.pack()

dropdown = ttk.OptionMenu(masterframe, value, *options)
dropdown.pack()

a.mainloop()

Источник: http://www.pyinmyeye.com/2012/08/tkinter-menubutton-demo.html

Ответ 4

У меня был такой же вопрос в другом посте. Я на самом деле прочитал этот пост и ответы, но не заметил тонких различий между этими двумя вариантами меню. Итак, здесь мой ответ также, хотя я новичок в Python и tkinter.

Как ответил @Bryan Oakley, да, строка документа показывает, что при использовании ttk.OptionMenu вместо tk.OptionMenu есть "дополнительный" обязательный параметр. Эта разница сломает (или, по крайней мере, испортит) ваше меню, если вы невольно измените объявление с ttk.OptionMenu обратно на tk.OptionMenu. Это потому, что tk.OptionMenu не требует, чтобы опция 'default' была объявлена. Если вы по какой-то причине измените ttk.OptionMenu на tk.OptionMenu и оставите параметр "по умолчанию" в объявлении, это дублирует первый параметр в OptionMenu. Я бился головой о стену, чтобы понять, почему эти двое не ведут себя точно так же. По моему личному мнению, это не должно быть так. Во всяком случае, параметр 'default' должен быть ключевым словом в tk.OptionMenu и ttk.OptionMenu для совместимости. Может быть, я ошибаюсь, но это мое мнение в данный момент.

Чтобы продемонстрировать это, посмотрите код ниже:

# test-optionmenu.py

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
# tk OptionMenu lists
optionList1 = ('a', 'b', 'c')
optionList2 = ('d', 'e', 'f')
optionList3 = ('g', 'h', 'j')
# ttk OptionMenu lists
optionList4 = ('1', '2', '3')
optionList5 = ('4', '5', '6')
optionList6 = ('7', '8', '9')
optionList7 = ('z', 'x', 'y')
# Set up the StringVars for each OptionMenu
v1 = tk.StringVar()
v2 = tk.StringVar()
v3 = tk.StringVar()
v4 = tk.StringVar()
v5 = tk.StringVar()
v6 = tk.StringVar()
v7 = tk.StringVar()

# tk.OptionMenu requires the default option
# to be declared via the set() method.
v2.set(optionList2[1]) # Default tk.OptionMenu value for om2
v3.set(optionList3[2]) # Default tk.OptionMenu item value for om3
v5.set(optionList5[1]) # Default ttk.OptionMenu item value for om5

# -------------------------------------------
# tk OptionMenu om1 does not automatically
# assign a default based on your list, so
# this does not display a list item initially
om1 = tk.OptionMenu(root, v1, *optionList1)

# -------------------------------------------
# om2 demonstrates the 'default' parameter
# from a former ttk.OptionMenu is ignored by
# tk.OptionMenu because it needs to have the
# default list item set via v2.set() call.
# Notice the 'e' is displayed initially as
# set, but now 'd' is duplicated in the list
# as a remnant of the former ttk.OptionMenu
# 'default' parameter.
om2 = tk.OptionMenu(root, v2, optionList2[0], *optionList2)

# -------------------------------------------
# om3 is a tk.OptionMenu and has no 'default'
# paramter declared like om2 above does.  Its
# default is set to option 2, or 'j', and is
# initially displayed on the dropdown.  None
# of the OptionMenu list items are duplicated.
om3 = tk.OptionMenu(root, v3, *optionList3)

# -------------------------------------------
# om4 shows how the 'default' parameter
# from a former ttk.OptionMenu is ignored by
# tk.OptionMenu because it needs to have the
# default list item set via v4.set() call.
# Since v4 is not set, nothing at all is
# diplayed initially and when the OptionMenu
# is clicked, it will show that '1' is listed
# twice.
om4 = tk.OptionMenu(root, v4, optionList4[0], *optionList4)

# -------------------------------------------
# by changing a tk.OptionMenu to a
# ttk.OptionMenu, without properly declaring
# the default OptionMenu item in the ttk way
# will result in item '5' not being displayed
# initially, and '4' will not be displayed in
# the OptionMenu choices after a choice has
# been made.
om5 = ttk.OptionMenu(root, v5, *optionList5)

# -------------------------------------------
# om6 is the same as om5, except it does not
# have a tk.OptionMenu default declared.  It
# is only here for consiceness.
om6 = ttk.OptionMenu(root, v6, *optionList6)

# -------------------------------------------
# om7 is the proper way to declare a
# ttk.OptionMenu, with a default option
# initially set.
om7 = ttk.OptionMenu(root, v7, optionList7[2], *optionList7)

# Pack'em all up
om1.pack()
om2.pack()
om3.pack()
om4.pack()
om5.pack()
om6.pack()
om7.pack()

# Execute the mainloop
root.mainloop()

Я знаю, что код может быть уродливым для некоторых, и если вы действительно хотите изменить его, продолжайте. :)