Python tkinter中的多个optionmenus跟踪语句不起作用

问题描述 投票:-2回答:1

我已经为Windows编写了一个Python程序,它显示在一个表中,设备的传出IP地址与进程,程序和使用它的其他数据结合在一起。

我正在使用单独的Listbox小部件来处理IP地址,进程和程序。

由于每个框中都有很多信息,我试图在每个列表框上都有一个过滤器,以便用户可以查看特定的进程和他们正在使用的IP。

我试图使用optionmenu小部件来实现过滤器。因此每个列表框中都有一个optionmenu,optionmenu中的值取决于该列表框的输出。从该列表框的optionmenu中选择一个值时,该列表框应仅显示所选值以及其他列表框中的相应值。

代码的一部分如下所示:

def change_dropdown(term, listboxValues):

    fill_in_listboxes.change = True

    deleteListbox()

    change_dropdown.ind_list = getIndex(term, listboxValues)

    #print(change_dropdown.ind_list)

    insert(fill_in_listboxes.processList, processListbox, change_dropdown.ind_list)
    insert(fill_in_listboxes.programList, programListbox, change_dropdown.ind_list)


processVar.trace('w', lambda *args: change_dropdown(processVar.get(), fill_in_listboxes.processList))
programVar.trace('w', lambda *args: change_dropdown(programVar.get(), fill_in_listboxes.programList))

change_dropdown函数最初通过调用单独的函数删除列表框中的所有值:

deleteListbox()

它调用一个函数,该函数创建一个全局变量数字列表,该列表对应于所选值的索引;这是基于从optionmenu中选择的值,并根据列表框中的整个值列表进行检查:

change_dropdown.ind_list = getIndex(term, listboxValues))

然后,它使用每个列表框的整个数据集(这是在另一个函数中创建的全局变量),列表框对象本身以及上面创建的索引列表,以将过滤后的值数据插入到列表框中:

insert(fill_in_listboxes.processList, processListbox, change_dropdown.ind_list)
insert(fill_in_listboxes.programList, programListbox, change_dropdown.ind_list)

使用optionmenus时,我知道需要创建一个跟踪功能(?),以便在任何时候更改optionmenu时进行监听。

我不想为每个跟踪调用创建单独的函数,所以我从stackoverflow页面找到了一些信息,它似乎提供了一种方法来为每个optionmenu进行跟踪调用,它调用了相同的函数:

processVar.trace('w', lambda *args: change_dropdown(processVar.get(), fill_in_listboxes.processList))
programVar.trace('w', lambda *args: change_dropdown(programVar.get(), fill_in_listboxes.programList))

Stackoverflow页面:

Getting the choice of optionmenu right after selection Python

使用Kevin的答案。

这是没有过滤器的前两个列框的图像:

Unfiltered columns

这是使用第一列过滤时的样子:

First column filtered

这是尝试过滤第二列时的样子:

Attempts at filtering on second column

我知道出了什么问题,但我不知道为什么。在这一行:

programVar.trace('w', lambda *args: change_dropdown(programVar.get(), fill_in_listboxes.programList))

第二个变量与programList列表框中找到的所有值相关。与此列表框相关的值列表是名为fill_in_listboxes.programList的全局变量。但是,当我通过在参数上使用print()命令检查以查看实际传递给change_dropdown函数的内容时,它实际上传递了进程Listbox中的值,(fill_in_listboxes.processList)

我很困惑,因为当我检查传递给change_dropdown()函数的值时,programVar,get()的值是正确的,但fill_in_listboxes.processList已作为第二个参数传递。

这意味着当我尝试从第二个列表框中获取我选择的值的索引时,找不到它,因为它试图从第一个列表框中找到该值!

我相信这个问题可能与lambda和closures有关,但我不太了解python,足以理解我哪里出错了。我希望有人能够提供一些帮助。

python tkinter lambda
1个回答
1
投票

我找到了自己问题的答案。

最初在创建OptionMenus时,我只添加了一个字符串变量“All”作为占位符。

随后,当相应的列表框中填充了值时,与该列表框关联的选项菜单将填充列表框中的各个唯一值。

随后使用以下函数实现了optionmenu ['menu']属性的后续填充:

def changeMenu(value, listSet, menuObj):

if not(value in listSet):
    listSet.add(value)
    menuObj.add_command(label=value, command=lambda s=value: processVar.set(s))

'value'是从列表框中添加到optionmenu的单个值。它是针对该选项菜单的已添加值的Python集合进行检查的,(参数'listset')如果它不存在,那么我使用菜单小部件add_command函数将值添加到列表中。但是在上面的代码中,与值关联的函数链接到var变量processVar。这对应于processListBox和与列表框关联的选项菜单。)

我现在认为这意味着无论何时生成其他菜单中的选项,它总是会查看与processVar相关的跟踪。因此,我将上面的代码更改为:

def changeMenu(value, listSet, menuObj, varObj):

if not(value in listSet):
    listSet.add(value)
    menuObj.add_command(label=value, command=lambda s=value: varObj.set(s))

当调用changeMenu函数时,varObj参数将与optionmenu的链接var变量相关。

随后的测试显示该解决方案有效。

© www.soinside.com 2019 - 2024. All rights reserved.