tkinter OptionMenu 问题(bug?):GUI 和程序值未保持同步(python 3.x)

2024-02-17

在某些情况下(下面的演示),OpenMenu 小部件上显示的值与程序使用的值不匹配,这会导致当用户期望选项 A 时执行选项 B - 导致 WTF?用户的反应。

不幸的是,OptionMenu 小部件没有我与其他小部件一起使用来轻松处理问题的“命令”选项(例如演示中的“A_Button”小部件)。我尝试过使用绑定,但到目前为止我还没有解决问题的“灵丹妙药”。

我检查了常用的地方(NMT、effbot、这里等),发现这个小部件几乎没有有用的文档,特别是在处理下拉列表中的项目时。 (知道如何确定列表中的项目数,列表中当前选定值的位置/索引以及如何将小部件包含在 GUI 的选项卡序列中将会很有用)。

我的申请是多语言的;当语言改变显示值时andOptionMenu 小部件的下拉列表必须相应更改。 (顺便说一句,多语言意味着您不能在代码中直接使用 .get() 的结果,特别是在添加另一种语言的情况下。为了获得语言独立性,我使用通过将 .get() 值与值匹配而创建的索引在选项菜单中 - 有更好的方法吗?)

在演示代码中,所选语言决定 OptionMenu 小部件显示的值。 “使用日期”(按钮小部件)正是实际应用程序的启动方式(以及为什么强制 GUI 和程序值始终匹配 - 这并不总是发生)。相比之下,“今天是什么日子?” (也是一个按钮小部件)使用命令选项来实现预期/正确的行为 - 正如我的应用程序中多次成功完成的那样。

要查看问题,请运行演示,选择任意语言。在不改变语言的情况下,日子会多次改变。请注意,打印值(由我的应用程序使用)始终是 GUI 小部件上显示的值后面的一个选择。接下来,在不更改日期的情况下,选择不同的语言(将打印新语言)。 OptionMenu 下拉值不会更改,直到after鼠标离开 OptionMenu 小部件 - 及其显示的值never被“翻译”成新语言。

我忽略/遗漏/做错了什么?

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>'具有约束力,但让我们尝试一般性地回答您的问题:

  1. Unfortunately the OptionMenu widget does not have the "command" option that I've used with other widgets to easily handle the problem (e.g. "A_Button" widget in demo).

你错了,因为它有这个option https://www.tcl.tk/man/tcl/TkCmd/menu.htm#M55:

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_bar.__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. ...the position/index of the currently selected value in the list...

再说一次,有一个option https://www.tcl.tk/man/tcl/TkCmd/menu.htm#M39为了那个原因:

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. ...determine the number of items in the list...

这也是可以实现的,因为项目数只是最后一个索引 + 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都解决了。当然,堆叠顺序除外,但您可以更换您的OptionMenu with ttk.Combobox随时。没有这样的<Tab>, 行为Menu小部件,因为它们对命令的反应不同,例如lift。当然,这也是可以实现的,但这是另一个问题,因为有越来越多的“假设”!

就这样!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

tkinter OptionMenu 问题(bug?):GUI 和程序值未保持同步(python 3.x) 的相关文章

随机推荐

  • C++ int a[n] 在 g++ 中工作但不能在 vs2008 中工作

    我有以下代码 int n cin gt gt n int numbers n 它在 Mac 上使用 g 我认为 通过 NetBeans 进行编译 而在 Windows 上则无法使用 VS2008 进行编译 为什么让它适用于每个编译器如此困难
  • SQL Server 2k5内存消耗?

    我有一个正在运行 sql server 的开发虚拟机以及我的堆栈的一些其他应用程序 我发现其他应用程序的性能非常糟糕 经过一番挖掘后 SQL Server 占用了内存 经过快速的网络搜索后 我发现默认情况下 它会消耗尽可能多的内存来缓存数据
  • Java 反射,getMethod()

    我正在研究 Java 反射的基础知识并观察类方法的信息 我需要获取一个与 getMethod 函数所描述的规范相匹配的方法 然而 当我这样做时 我得到一个 NoSuchMethodException 我希望你能告诉我为什么我的实现不正确 s
  • 如何删除旧版 Web 应用程序中的 CSS 意大利面?

    在开发了几个大型 Web 应用程序并看到没有清晰结构的巨大样式表之后 我真的很想知道人们是否找到了方法来保持大型复杂 Web 应用程序的 CSS 干净 如何从遗留的 混乱的 CSS 转向干净的 漂亮的级联 DRY 样式表 我目前正在开发的应
  • 为什么不使用工厂模式进行排序? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 有没有一种优雅的方法来解析单词并在大写字母前添加空格

    我需要解析一些数据并且我想转换 AutomaticTrackingSystem to Automatic Tracking System 本质上是在任何大写字母之前放置一个空格 当然除了第一个字母 您可以使用环视 例如 string tes
  • 在 Mac 上覆盖 python 3.x 中的打印行

    我正在尝试编写一个涉及使用硬币翻转 正面或反面的程序 但这样它会打印 正面 然后用 反面 替换 并继续这样做 直到决定答案 目前 当我运行该程序时 它每次都会在下一行打印 正面 或 背面 这种情况在空闲和终端上都会发生 我尝试过使用回车符
  • 在运行时创建证书和通行证类型 ID

    我的 Passbook 相关应用最近根据准则 23 3 被拒绝 23 3 通行证必须由将以其自己的名称 商标或品牌分发通行证的实体签署 否则应用程序将被拒绝 并且 Passbook 凭据可能会被撤销 我有几个问题 并与苹果公司的某人通了电话
  • jQuery 和 IE 在 $('#someDiv').hide(); 上崩溃

    好吧 过了一会儿我挠了挠头 啊 试图找出为什么 IE 在加载我的一个加载了 jQuery 的页面时会直接崩溃 我将罪魁祸首缩小到这一行 div questions hide 当我说 IE 崩溃时 我的意思是它完全崩溃了 试图进行网页恢复 但
  • 在 https:// 上使用 ws://(混合内容)

    我有一个 html5 页面 var connection new WebSocket ws foo bar 8888 但我收到一个错误 混合内容 页面位于 https foo bar https foo bar 通过 HTTPS 加载 但尝
  • PHP PDO 准备好的语句需要转义吗?

    On the PDO 准备页面 http www php net manual en pdo prepare php它指出 并且无需手动引用参数 有助于防止 SQL 注入攻击 知道了这一点 是否有像 mysql real escape st
  • 将 git 与 CVS 结合使用的最佳实践

    使用 git 与 CVS 存储库交互的最佳实践和技巧是什么 我写了一个类似问题的答案here https stackoverflow com questions 584522 how to export revision history f
  • 按钮是否允许显示:网格? [复制]

    这个问题在这里已经有答案了 按钮是否允许显示 网格 或者更一般地说 是否有任何元素不能使用display grid 考虑 button div display grid grid template columns 50px 50px Nev
  • 从 DOS 命令行关闭正在运行的应用程序

    start 命令可以在批处理文件中启动像记事本这样的应用程序 如下所示 start notepad start my love mp3 但是如何从命令行关闭正在运行的应用程序呢 我发现taskkill在我的搜索中 但我认为这不是正确的命令
  • 如何显示当前运行的python模块的路径? [复制]

    这个问题在这里已经有答案了 如何显示当前运行的python模块的路径 哪个会打印 Users user documents python bla py如果 bla py 被放置在 Users user documents python 如果
  • 将二进制格式字符串转换为 int,在 C 中

    如何将二进制字符串 如 010011101 转换为 int 以及如何将 int 如 5 转换为 C 中的字符串 101 The strtol标准库中的函数采用 base 参数 在本例中为 2 int fromBinary const cha
  • S3 上的静态网站,路由为 53 - 无法访问网站

    我在 S3 上托管了一个静态网站 并设置了合适的存储桶策略 在另一个选项卡中查看 端点 效果非常好 此后 我在路线 53 中创建了一个托管区域 为其提供了理想的人类可读地址 创建托管区域后 我新创建的托管区域中有两条记录 其中一条记录属于类
  • Django 根据子级过滤父级

    我有发票型号 class Invoice models Model name models ForeignKey Patient on delete models CASCADE 我有另一个发票金额模型 其中包含发票的 FK class I
  • Firebase 远程通知未收到?

    我尝试通过云消息从 Firebase 控制台发送远程通知 但我的手机没有收到任何警报 我已将证书上传到 Firebase 并且正在使用 Firebase 教程提供的默认代码来接收通知 Here is a picture of my cert
  • tkinter OptionMenu 问题(bug?):GUI 和程序值未保持同步(python 3.x)

    在某些情况下 下面的演示 OpenMenu 小部件上显示的值与程序使用的值不匹配 这会导致当用户期望选项 A 时执行选项 B 导致 WTF 用户的反应 不幸的是 OptionMenu 小部件没有我与其他小部件一起使用来轻松处理问题的 命令