我已经编写了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
使用凯文的答案。
这是前两个没有过滤器的列框的图像:
使用第一列进行过滤时的外观如下:
这是尝试在第二列上进行过滤时的样子:
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的了解并不深,无法理解我哪里出了问题。我希望有人能够提供帮助。
答案 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变量相关。
后续测试表明该解决方案有效。