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

时间:2018-09-10 18:35:29

标签: python tkinter lambda

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

我正在使用单独的列表框小部件来存储IP地址,进程和程序。

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

我尝试使用 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()

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

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页面上找到了信息,该信息似乎提供了对每个选项菜单进行跟踪调用的方法,该调用了相同的函数:

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

使用凯文的答案。

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

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函数的内容时,它实际上是从进程列表框( fill_in_listboxes.processList

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

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

我相信问题可能与lambda和闭包有关,但我对python的了解并不深,无法理解我哪里出了问题。我希望有人能够提供帮助。

1 个答案:

答案 0 :(得分:1)

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

最初,在创建OptionMenu时,我仅添加了一个字符串变量“ 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))

“值”是从列表框中获取的将添加到选项菜单的单个值。已针对该选项菜单的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变量相关。

后续测试表明该解决方案有效。