问题描述
问题集:
上下文菜单应动态显示过滤器变量并使用回调中定义的参数执行函数.通用描述显示正确,但函数调用始终使用最后设置的选项执行.
Context Menu should show filter variables dynamically and execute a function with parameters defined inside the callback.Generic descriptions show properly, but function call is always executed with last set option.
我尝试过的:
#!/usr/bin/env python
import Tkinter as tk
import ttk
from TkTreectrl import MultiListbox
class SomeClass(ttk.Frame):
def __init__(self, *args, **kwargs):
ttk.Frame.__init__(self, *args, **kwargs)
self.pack(expand=True, fill=tk.BOTH)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.View=MultiListbox(self)
__columns=("Date","Time","Type","File","Line","-","Function","Message")
self.View.configure(columns=__columns, expandcolumns=(0,0,0,0,0,0,0,1))
self.View.bind("", self.cell_context)
self.View.grid(row=0, column=0, sticky=tk.NW+tk.SE)
self.__recordset = []
self.__recordset_filtered = False
#Some dummy values
self.__recordset.append(["Date", "Time", "INFO", "File", "12", "-", "Function", "Message Info"])
self.__recordset.append(["Date", "Time", "DEBUG", "File", "12", "-", "Function", "Message Info"])
self.__recordset.append(["Date", "Time", "WARNING", "File", "12", "-", "Function", "Message Info"])
self.__refresh()
def cleanView(self):
self.View.delete(0, tk.END)
def __refresh(self):
self.cleanView()
for row in self.__recordset:
self.View.insert(tk.END, *row)
def filter_records(self, column, value):
print("Filter Log Recordset by {column} and {value}".format(**locals()))
# Filter functionality works as expected
# [...]
def cell_context(self, event):
__cMenu=tk.Menu(self, tearoff=0)
if self.__recordset_filtered:
__cMenu.add_command(label="Show all", command=lambda: filter_records(0, ""))
else:
column=2
options=["INFO", "WARNING", "DEBUG"]
for i in range(len(options)):
option=options[i]
__cMenu.add_command(label="{}".format(option), command=lambda: self.filter_records(column, option))
# Also tried using for option in options here with same result as now
__cMenu.post(event.x_root, event.y_root)
if __name__=="__main__":
root=tk.Tk()
app=SomeClass(root)
root.mainloop()
我得到的当前输出是:
按 2 和 DEBUG 过滤日志记录集
无论我选择三个选项中的哪一个.我认为它与垃圾收集有关,只剩下最后一个选项,但我不知道如何避免这种情况.
No matter which of the three options i choose. I assume it has sth to do with the garbage collection that only the last option remains but i cannot figure out how to avoid this.
建议提供任何帮助.
推荐答案
请阅读最小示例.如果没有阅读您的代码,我相信您已经遇到了之前的问题和答案中解决的一个众所周知的问题,需要 2 行来说明.函数体中的名称在函数执行时被评估.
Please read about minimal examples. Without reading your code, I believe you have run into a well known issue addressed in previous questions and answers that needs 2 lines to illustrate. Names in function bodies are evaluated when the function is executed.
funcs = [lambda: i for i in range(3)]
for f in funcs: print(f())
打印 '2' 3 次,因为 3 个函数是相同的,并且每个函数中的 'i' 直到调用时才计算,当 i == 2 时.然而,
prints '2' 3 times because the 3 functions are identical and the 'i' in each is not evaluated until the call, when i == 2. However,
funcs = [lambda i=i:i for i in range(3)]
for f in funcs: print(f())
生成三个不同的函数,每个函数都有不同的捕获值,因此打印了 0、1 和 2.在你的声明中
makes three different functions, each with a different captured value, so 0, 1, and 2 are printed. In your statement
__cMenu.add_command(label="{}".format(option),
command=lambda: self.filter_records(column, option))
在:
之前添加option=option
来捕获option
的不同值.你可能想重写为
add option=option
before :
to capture the different values of option
. You might want to rewrite as
lambda opt=option: self.filter_records(column, opt)
将循环变量与函数参数区分开来.如果 column
在循环内发生变化,则需要相同的处理.
to differentiate the loop variable from the function parameter. If column
changed within the loop, it would need the same treatment.
这篇关于for 循环中的 lambda 只取最后一个值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!