Tkinter的OptionMenu问题(错误):GUI和程序不值保持步调一致(蟒蛇3.X)

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() 
+1

在您编写代码的开始处“您可以跳过所有这些常量......”。如果我们可以跳过它们,为什么要发布它们?请花时间创建一个[mcve]。 –

+0

评论被放置在那里,所以你不必浪费时间看着gruntwork来设置demo所使用的stati表。有必要设置e评论iwas inteded ts intede to make你可以跳过那些部分,因为gruntwork需要设置 – user1459519

+1

正如我所说,如果它不需要在那里重现问题,你应该删除它。如果你期望得到帮助,你必须愿意付出一点努力。 –

你的程序的逻辑不清晰对我来说,尤其是'<Leave>'约束力,但让我们尝试回答您的问题一般:

  1. 不幸的是,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() 
  1. ...的位置/索引列表中的当前所选的值的...

再次,还有该一个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. ...确定列表中的项目数...

  2. 这也是可以实现的,因为项目的数量仅仅是最后一个索引+ 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等命令的反应不同。当然,它也是可以实现的,但是这是另一个问题,因为有许多“假设”!

    就这样!

开始=>
+0

现在,这是tkinter中严重缺失的那种关键文档!有了它,我可以解决我的问题。顺便说一句,离开装订不应该在那里。对于长期延迟回馈给你,感到抱歉。这里有一个密切相关的问题。 https://stackoverflow.com/questions/48289554/python-tkinter-getting-the-number-of-entries-in-an-optionmenu-dropdown-list – user1459519

+0

在上述问题appering函数的输出是为什么我认为OptionMenu没有命令选项)。 – user1459519