python - Checkbutton 和 Entry(box) 之间的通信
问题描述
from tkinter import *
import pandas as pd
df = pd.DataFrame({'item': list('abcde'), 'default_vals': [2,6,4,5,1]})
def input_data(df):
box = Tk()
height = str(int(25*(df.shape[0]+2)))
box.geometry("320x" + height)
box.title("my box")
#initialise
params, checkButtons, intVars = [], [], []
default_vals = list(df.default_vals)
itemList = list(df.item)
for i,label in enumerate(itemList):
Label(box, text = label).grid(row = i, sticky = W)
params.append(Entry(box))
params[-1].grid(row = i, column = 1)
params[-1].insert(i, default_vals[i])
intVars.append(IntVar())
checkButtons.append(Checkbutton(variable = intVars[-1]))
checkButtons[-1].grid(row = i, column = 3)
def sumbit(event=None):
global fields, checked
fields = [params[i].get() for i in range(len(params))]
checked = [intVars[i].get() for i in range(len(intVars))]
box.destroy()
#add submit button
box.bind('<Return>', sumbit)
Button(box, text = "submit",
command = sumbit).grid(row = df.shape[0]+3, sticky = W)
box.focus_force()
mainloop()
return fields, checked
我是 tkinter 的新手,不确定我想做什么。
目前,我的脚本(这里简化为函数而不是类)构建了一个框,其中包含在字段中输入的所有默认值:
相反,我想从空字段开始,一旦单击相应的 checkButton 将获得默认值(应该仍然能够像现在一样通过字段手动更改它),而且,一旦在给定中输入任何值字段,对应的checkButton被选中。
这些可能吗?
解决方案
这是可能的,但让我在我的解决方案前对您当前的代码提出一些注意事项:
很少建议进行星号导入 (
from tkinter import *
),因为您无法控制导入命名空间的内容。最好明确导入您需要的内容作为参考:import tkinter as tk tk.Label() # same as if you wrote Label() tk.IntVar() # same as if you called IntVar()
您想要的行为虽然可能,但不一定是用户友好的。当用户已经输入了某些内容并取消选中该复选框时会发生什么?或者如果选择了复选框然后用户删除了信息会发生什么?这些可能是您要考虑的事情。
话虽如此,解决方案是trace
在变量上添加回调函数。您还需要StringVar()
为Entry
盒子添加一个,因为您想要一个双向连接:
# add strVars as a list of StringVar() for your Entry box
params, checkButtons, intVars, strVars = [], [], [], []
在您的 迭代期间enumerate(itemList)
,添加以下内容:
# Create new StringVar()
strVars.append(StringVar())
# add a trace callback for tracking changes over the StringVar()
strVars[-1].trace_add('write', lambda var, var_idx, oper, idx=i: trace_strVar(idx))
# update your Entry to set textvariable to the new strVar
params.append(Entry(box, textvariable=strVars[-1]))
# similarly, add a trace for your IntVar
intVars[-1].trace_add('write', lambda var, var_idx, oper, idx=i: trace_intVar(idx))
在迭代小部件创建之前,您需要定义两个trace
回调函数 :
def trace_intVar(idx):
# if Checkbox is checked and Entry is empty...
if intVars[idx].get() and not params[idx].get():
# prefill Entry with default value
params[idx].insert(0, df.default_vals[idx])
def trace_strVar(idx):
# if Entry has something...
if strVars[idx].get():
# and Checkbox is not checked...
if not intVars[idx].get():
# Set the checkbox to checked.
intVars[idx].set(True)
# but if Entry is empty...
else:
# Set the Checkbox to uncheck.
intVars[idx].set(False)
记住我提到了这种行为——我冒昧地清除了Checkbox
ifEntry
是空的。但是,如果您不想这样做,则需要稍微修改处理。
注意trace_add
书写方式。回调函数始终使用三个默认参数传递,即变量名称、变量索引(如果有)和操作(请参阅 Bryan Oakley 的这个好答案)。由于在这种情况下我们不需要任何参数(我们不能将变量名反向引用到变量之间的链接索引lists
),我们必须手动用另一个回调来包装回调lambda
并忽略三个参数:
lambda var, # reserve first pos for variable name
var_idx, # reserve second pos for variable index
oper, # reserve third pos for operation
idx=i: # pass in i by reference for indexing point
trace_intVar(idx) # only pass in the idx
在这种情况下,您不能只传递值lambda...: trace_intVar(i)
而i
不是引用传递。相信我,我以前犯过这个错误。因此,我们传递另一个参数idx
,其默认设置为i
,现在将通过引用传递。
如果trace_add
不起作用,请trace('w', ...)
改用。
为了繁荣,这是您问题的完整实施解决方案:
from tkinter import *
import pandas as pd
df = pd.DataFrame({'item': list('abcde'), 'default_vals': [2,6,4,5,1]})
def input_data(df):
box = Tk()
height = str(int(25*(df.shape[0]+2)))
box.geometry("320x" + height)
box.title("my box")
#initialise
params, checkButtons, intVars, strVars = [], [], [], []
default_vals = list(df.default_vals)
itemList = list(df.item)
def trace_intVar(idx):
if intVars[idx].get() and not params[idx].get():
params[idx].insert(0, df.default_vals[idx])
def trace_strVar(idx):
if strVars[idx].get():
if not intVars[idx].get():
intVars[idx].set(True)
else:
intVars[idx].set(False)
for i,label in enumerate(itemList):
Label(box, text = label).grid(row = i, sticky = W)
strVars.append(StringVar())
strVars[-1].trace_add('write', lambda var, var_idx, oper, idx=i: trace_strVar(idx))
params.append(Entry(box, textvariable=strVars[-1]))
params[-1].grid(row = i, column = 1)
#params[-1].insert(i, default_vals[i]) # <-- You don't need this any more
intVars.append(IntVar())
intVars[-1].trace_add('write', lambda var, var_idx, oper, idx=i: trace_intVar(idx))
checkButtons.append(Checkbutton(variable = intVars[-1]))
checkButtons[-1].grid(row = i, column = 3)
def sumbit(event=None):
global fields, checked
fields = [params[i].get() for i in range(len(params))]
checked = [intVars[i].get() for i in range(len(intVars))]
box.destroy()
#add submit button
box.bind('<Return>', sumbit)
Button(box, text = "submit",
command = sumbit).grid(row = df.shape[0]+3, sticky = W)
box.focus_force()
mainloop()
return fields, checked
推荐阅读
- mysql - MariaDB:某些查询中没有选择数据库错误
- python-3.x - Pylint 错误:'optparse.OptionValueError:选项拼写字典:无效值:'en_US',应该在 ['']'
- reactjs - 如何通过 json 文件将图像从公共文件夹导入 React
- .htaccess - htaccess int:tolower 多次重定向
- heroku - 默认情况下是否可以使用免费的测功机来审查应用程序?
- django - 如何使用 django 查询集获得唯一的结果?
- c++ - 对“pair<...>”类型的非常量左值引用不能绑定到“pair<...>”类型的临时值
- powershell - 执行 chef inspec 命令时收到的错误
- python - 如何在python中计算多变量非线性回归?
- angular - Angular 6 烤面包机通知模块