我已经为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的答案。
这是没有过滤器的前两个列框的图像:
这是使用第一列过滤时的样子:
这是尝试过滤第二列时的样子:
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,足以理解我哪里出错了。我希望有人能够提供一些帮助。
我找到了自己问题的答案。
最初在创建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变量相关。
随后的测试显示该解决方案有效。