Python Tkinter选项菜单用于复制显示值的唯一标识符

Python Tkinter选项菜单用于复制显示值的唯一标识符,python,tkinter,optionmenu,Python,Tkinter,Optionmenu,以这个问题为基础—— 回答代码如下: import Tkinter as tk master = tk.Tk() variable = tk.StringVar(master) options = {"one": 1, "two": 2} tk.OptionMenu(master, variable, *options.keys()).pack() ... wanted = options[variable.get()] 但是,我希望我的整数值可以用作唯一标识符,即使字符串可能是相同的。见下文

以这个问题为基础——

回答代码如下:

import Tkinter as tk
master = tk.Tk()
variable = tk.StringVar(master)
options = {"one": 1, "two": 2}
tk.OptionMenu(master, variable, *options.keys()).pack()
...
wanted = options[variable.get()]
但是,我希望我的整数值可以用作唯一标识符,即使字符串可能是相同的。见下文

# this will overwrite the "a" value to be 3
# the first entry will be lost
options = {"a": 1, "b": 2, "a": 3}

# so instead switch the order...
options = {1: "a", 2: "b", 3: "a"}
# then we can use values() to provide the options
tk.OptionMenu(master, variable, *options.values()).pack()
...
# but now how do I replace this line 
# to get the correct identifier for the option chosen?
wanted = options[variable.get()]

选项菜单中是否可能有重复的显示文本链接回正确的唯一标识符?

下面是我解决此问题的方法。我扩展了自己的StringVar类,并重新实现了OptionMenu类。我把它放在他们自己的源文件中,我不建议“重写”tk实现

import tkinter as tk

class LinkedIntStringVar(tk.StringVar):
    '''Takes a dictionary of int to strings. default 'get' function
        will return strings as normal, but there is also special function for
        returning based on the integer values 'get_int'.
    Setting the variable requires using the integer value set in int_string_dict'''
    def __init__(self, master=None, int_string_dict=None, value=None, name=None):
        tk.StringVar.__init__(self, master, value, name)
        self.__int_string_dict = int_string_dict
        self.__current_int_value = 0

    def get_int(self):
        """Return value of variable as integer."""
        return self.__current_int_value

    def set(self, value):
        """Set the variable to VALUE."""
        string_value = self.__int_string_dict[value]
        self.__current_int_value = value
        super().set(string_value)

# No changes from tkinter's implementation here, I just like it to be available.
class _setit:
    """Internal class. It wraps the command in the widget OptionMenu."""
    def __init__(self, var, value, callback=None):
        self.__value = value
        self.__var = var
        self.__callback = callback
    def __call__(self, *args):
        self.__var.set(self.__value)
        if self.__callback:
            self.__callback(self.__value, *args)

# Changes to this class are commented below
class OptionMenu(tk.Menubutton):
    """OptionMenu which allows the user to select a value from a menu."""
    def __init__(self, master, variable, values, **kwargs): # removed 'value' from args
        """Construct an optionmenu widget with the parent MASTER, with
        the resource textvariable set to VARIABLE, the initially selected
        value VALUE, the other menu values VALUES and an additional
        keyword argument command."""
        kw = {"borderwidth": 2, "textvariable": variable,
              "indicatoron": 1, "relief": tk.RAISED, "anchor": "c",
              "highlightthickness": 2}
        tk.Widget.__init__(self, master, "menubutton", kw)
        self.widgetName = 'tk_optionMenu'
        menu = self.__menu = tk.Menu(self, name="menu", tearoff=0)
        self.menuname = menu._w
        # 'command' is the only supported keyword
        callback = kwargs.get('command')
        if 'command' in kwargs:
            del kwargs['command']
        if kwargs:
            raise tk.TclError('unknown option -'+kwargs.keys()[0])
        # Issues with the variables clashing, 
        # I personally just depend on the variable's value so it was easiest 
        # just to remove this unneeded portion (for my case)
        #menu.add_command(label=value,
        #         command=_setit(variable, value, callback))
        for v in values.keys(): # Change this line to handle dict instead of list
            # Change this line to set to the String value in the dict
            menu.add_command(label=values[v],
                     command=_setit(variable, v, callback))
        self["menu"] = menu

    def __getitem__(self, name): # No changes
        if name == 'menu':
            return self.__menu
        return tk.Widget.__getitem__(self, name)

    def destroy(self): # No changes
        """Destroy this widget and the associated menu."""
        tk.Menubutton.destroy(self)
        self.__menu = None
下面是如何使用它的示例

# import the custom classes
import tkinter as tk

master = tk.Tk()

options = { 0: 'None', 1: 'Test', 2: 'Example', 3: 'Test'}
variable = LinkedIntStringVar(master, int_string_dict=options)
variable.set(0)

option_menu = OptionMenu(master, variable, options,
                         command=lambda value, *args: print('Changed to', value)).pack()
tk.mainloop()

您将看到回调中返回的整数值。字符串可以通过
variable.get()
返回,整数值也可以通过
variable.get\u int()

返回,用户应该如何知道选择哪个
a
s?这似乎是一个完全无法使用的UI设计。在选择
a
后,将显示更多详细信息,但这是假设我可以获得正确的标识符。您可以想象两个名为
a
的人,用户界面会显示更多细节,如地址、电话号码等