Tkinter的OptionMenu问题(错误):GUI和程序不值保持步调一致(蟒蛇3.X)
在某些情况下(演示下)在OpenMenu控件中显示的值不匹配,使用的程序,这将导致选项B在用户期待选项A时完成 - 导致WTF?用户的反应。Tkinter的OptionMenu问题(错误):GUI和程序不值保持步调一致(蟒蛇3.X)
不幸的是,OptionMenu小部件不具备“命令”选项,我已经与其他部件用于方便地处理这个问题(例如,“A_Button”小部件演示)。我试过使用绑定,但到目前为止,我还没有修复这个问题的“魔法子弹”。
我检查了老地方(NMT,effbot,在这里,等),并发现靠近任何有用的机制的文档在这个窗口部件,尤其是当它涉及到与下拉列表中的项目工作。 (了解如何确定列表中项目的数量,列表中当前选定值的位置/索引以及如何在GUI的选项卡序列中包含该小部件将很有用)。
我的申请是多种语言;当语言更改显示值和时,OptionMenu小部件的下拉列表必须相应更改。 (顺便说一句,多语言意味着你不能直接在代码中使用.get()的结果,特别是如果添加了另一种语言。为了获得语言独立性,我使用通过匹配.get()值和值在选项菜单 - 是否有更好的方法)
在演示代码所选择的语言确定由OptionMenu插件所示的值? “使用日期”(一个Button小部件)就是真正的应用程序启动的方式(以及GUI和程序值始终匹配的强制性要求 - 这并不总是发生)。相比之下,“它是哪一天?” (也是一个Button小部件)使用命令选项来实现预期的/正确的行为 - 在我的应用程序中已经成功完成了很多次。
要看到问题,运行演示,选择任何语言。不改变语言几次改变这一天。请注意,打印的值(由我的应用程序使用)始终是GUI小部件上显示的值的一个选择。接下来,不改变日子,选择不同的语言(打印新语言)。该OptionMenu下拉值不会改变,直到后鼠标离开OptionMenu部件 - 永不被“翻译”成新语言的显示值。
我在看什么/错过/做错了什么?
from tkinter import Button, IntVar, Label, OptionMenu, Radiobutton, Tk, StringVar
# You can skip over this section, it's basic gruntwork needed to set up the demo (values used have no impact on the problem).
English = 0
French = 1
Spanish = 2
DayNumbers = 3
DefaultDay = 2 # Corresponds to Tuesday, emulates the user's choice of day (on the GUI)
DefaultLanguage = English
Languages = [ "English", "French", "Spanish", "Day Numbers" ] # for use on GUI
EnglishWeekdays = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]
FrenchWeekdays = [ "dimanche", "lundi", "mardi", "mecredi", "jeudi", "vendredi", "samedi" ]
SpanishWeekdays = [ "domingo", "lunes", "martes", "miercoles", "jeuves", "viernes", "sabado" ]
NumberedWeekdays = [ "Day 0", "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6" ]
DayNames = [ EnglishWeekdays, FrenchWeekdays, SpanishWeekdays, NumberedWeekdays ]
# The variables
LanguageInUse = DefaultLanguage
Weekdays = DayNames[ LanguageInUse ]
Today = DefaultDay # Isolates application code from language on GUI
#-------------------------------------------------------------------------------
def ChooseLanguage(ParentFrame) :
global LanguageInUse, DropdownMenu
GUI_Language = IntVar(value = LanguageInUse)
#---------------------------------------------------------------------------
def SwitchLanguage():
global LanguageInUse , Weekdays
LanguageInUse = GUI_Language.get()
print("SwitchLanguage sets language index to", LanguageInUse, "(" + Languages[ LanguageInUse ] + ")" )
Weekdays = DayNames[ LanguageInUse ]
DropdownMenu[ 'menu' ][ 'title' ] = Weekdays[ Today ]
for i, DayName in enumerate(Weekdays) :
DropdownMenu[ 'menu' ].entryconfig(i)['label' ] = DayName
return
#---------------------------------------------------------------------------
LanguageButton = []
for LanguageIndex, Language in enumerate(Languages) :
LanguageButton = LanguageButton + [ Radiobutton(ParentFrame,
indicatoron = False, width = 12,
variable = GUI_Language, command = lambda: SwitchLanguage(),
text = Language, value = LanguageIndex) ]
LanguageButton[ LanguageIndex ].grid(row = 0 , column = LanguageIndex)
return
#-------------------------------------------------------------------------------
def GetDayIndex() :
global Today, DropdownMenu
Today = 0
for Index, DayName in enumerate(Weekdays) :
if (GUI_Value.get() == DayName) :
Today = Index
break
print("GetDayIndex sets weekday index to", Today, "(" + Weekdays[ Today ] + ")")
for i, j in enumerate(Weekdays) :
DropdownMenu[ 'menu' ].entryconfig(i , label = j)
return
#-------------------------------------------------------------------------------
def DoSomethingUseful() :
print(" Program uses " + str(Today) + " (" + Weekdays[ Today ] +")")
return
#-------------------------------------------------------------------------------
# The mainline
root = Tk()
GUI_Value = StringVar(value = Weekdays[ Today ])
Widget1 = Label(root, text = "Today is")
Widget1.grid(row = 1, column = 0)
DropdownMenu = OptionMenu( root, GUI_Value, *DayNames[ LanguageInUse ]) # NOT in TAB key sequence !!!
DropdownMenu.grid(row = 1, column = 1 )
DropdownMenu.bind("<Leave>", lambda _ : GetDayIndex())
#OptionMenu_Configuration(DropdownMenu)
A_Button = Button(root, text = "What day is it??", command = lambda : GetDayIndex())
B_Button = Button(root, text = "Use the date", command = lambda: DoSomethingUseful())
A_Button.grid(row = 1, column = 2)
B_Button.grid(row = 1, column = 3)
ChooseLanguage(root) # creates/manages the language choice widgets
root.mainloop()
你的程序的逻辑不清晰对我来说,尤其是'<Leave>'
约束力,但让我们尝试回答您的问题一般:
-
不幸的是,OptionMenu小部件不具备“命令“选项,我已经与其他小部件一起使用来轻松处理问题(例如,演示中的”A_Button“小部件)。
你错了,因为它是有option:
import tkinter as tk
def dropdown_callback(selected=None):
print('Currently selected value is:\t%s' % selected)
root = tk.Tk()
str_var = tk.StringVar()
dropdown_menu = tk.OptionMenu(root, str_var, *['foo', 'bar', 'baz'], command=dropdown_callback)
dropdown_menu.pack()
root.mainloop()
此外,您还可以指定每个条目(很少使用)的单独command
:
import tkinter as tk
def dropdown_callback(event=None):
print('Currently selected value is:\t%s' % event)
def dropdown_callback_foo():
print('Called callback is:\t%s' % dropdown_callback_foo.__name__)
def dropdown_callback_bar():
print('Called callback is:\t%s' % dropdown_callback_foo.__name__)
root = tk.Tk()
str_var = tk.StringVar()
dropdown_menu = tk.OptionMenu(root, str_var, *['foo', 'bar', 'baz'], command=dropdown_callback)
dropdown_menu._OptionMenu__menu.entryconfig(0, command=dropdown_callback_foo)
dropdown_menu._OptionMenu__menu.entryconfig(1, command=dropdown_callback_bar)
dropdown_menu.pack()
root.mainloop()
-
...的位置/索引列表中的当前所选的值的...
再次,还有该一个option:
import tkinter as tk
def dropdown_callback(selected=None):
selected_index = root.tk.call(dropdown_menu.menuname, 'index', selected)
print('Currently selected value is:\t%s\t\ton position:\t%d' % (selected, selected_index))
root = tk.Tk()
str_var = tk.StringVar()
dropdown_menu = tk.OptionMenu(root, str_var, *['foo', 'bar', 'baz'], command=dropdown_callback)
dropdown_menu.pack()
root.mainloop()
-
...确定列表中的项目数...
这也是可以实现的,因为项目的数量仅仅是最后一个索引+ 1:
import tkinter as tk
def dropdown_callback(selected=None):
selected_index = root.tk.call(dropdown_menu.menuname, 'index', selected)
total_count = root.tk.call(dropdown_menu.menuname, 'index', 'end') + 1
print('Currently selected value is:\t%s\t\ton position:\t%d\t\twith total count:\t%d'
% (selected, selected_index, total_count))
root = tk.Tk()
str_var = tk.StringVar()
dropdown_menu = tk.OptionMenu(root, str_var, *['foo', 'bar', 'baz'], command=dropdown_callback)
dropdown_menu.pack()
root.mainloop()
从这一点来说,我认为,现在有OptionMenu
您的困惑都解决了。除了堆叠订单,当然,但您可以随时用ttk.Combobox
替换您的OptionMenu
。没有这样的<Tab>
,对于Menu
小部件的行为,因为它们对lift
等命令的反应不同。当然,它也是可以实现的,但是这是另一个问题,因为有许多“假设”!
就这样!
现在,这是tkinter中严重缺失的那种关键文档!有了它,我可以解决我的问题。顺便说一句,离开装订不应该在那里。对于长期延迟回馈给你,感到抱歉。这里有一个密切相关的问题。 https://stackoverflow.com/questions/48289554/python-tkinter-getting-the-number-of-entries-in-an-optionmenu-dropdown-list – user1459519
在上述问题appering函数的输出是为什么我认为OptionMenu没有命令选项)。 – user1459519
在您编写代码的开始处“您可以跳过所有这些常量......”。如果我们可以跳过它们,为什么要发布它们?请花时间创建一个[mcve]。 –
评论被放置在那里,所以你不必浪费时间看着gruntwork来设置demo所使用的stati表。有必要设置e评论iwas inteded ts intede to make你可以跳过那些部分,因为gruntwork需要设置 – user1459519
正如我所说,如果它不需要在那里重现问题,你应该删除它。如果你期望得到帮助,你必须愿意付出一点努力。 –