TKinter 中的一定数量的选择
certain number of choices in TKinter
我在 Tkinter 中制作了一个带有很多项目的检查栏,但我希望用户只能选择等于或少于一定数量的项目。这是我当前的代码:
from tkinter import *
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.vars = []
for pick in picks:
var = IntVar()
chk = Checkbutton(self, text=pick, variable=var)
chk.pack(side=side, anchor=anchor, expand=YES)
self.vars.append(var)
def state(self):
return [var.get() for var in self.vars]
root = Tk()
lng = Checkbar(root, range(10))
lng.pack(side=TOP, fill=BOTH)
root.mainloop()
检查栏需要检查按钮的最大数量和当前数量的属性。然后,您需要一个每次单击复选按钮时都会调用的命令。在 变量更改后 调用不带参数的命令。
如果可能,应发布不依赖于外部文件的代码。在这种情况下,只需传递一个字符串列表。 (我在 Aran-Fey 的编辑之前复制了。)
from tkinter import *
def checkmax(bar, var):
# called after the intvar is changed
def _check():
print(bar.numpicks, var.get())
if var.get(): # checked
if bar.numpicks < bar.maxpicks:
bar.numpicks += 1
else:
var.set(0)
else: # unchecked
bar.numpicks -= 1
return _check
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], maxpicks=2, side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.maxpicks = maxpicks
self.numpicks = 0
self.vars = []
for pick in picks:
var = IntVar()
chk = Checkbutton(self, text=pick, variable=var,
command=checkmax(self, var))
chk.pack(side=side, anchor=anchor, expand=YES)
self.vars.append(var)
def state(self):
return map((lambda var: var.get()), self.vars)
if __name__ == '__main__':
root = Tk()
lng = Checkbar(root, ['a', 'b', 'c', 'd'], 2)
lng.pack(side=TOP, fill=BOTH)
lng.config(relief=GROOVE, bd=2)
def allstates():
print( list(lng.state() ) )
Button(root, text = 'Quit', command = root.quit).pack(side = RIGHT)
Button(root, text = 'submit', command = allstates).pack(side = RIGHT)
root.mainloop()
您应该添加一个标签,说明可以检查的最大数量。
添加注释:当 Python IntVar 作为 Checkbutton 变量传递时,它被没有 .get 和 .set 方法的 _tkinter.Tcl_Obj 替换。因此该命令需要引用 IntVar 实例,因为 chk['variable'].get 不起作用。
这可以通过在选中最大数量的 CheckButton 时禁用所有未选中的 CheckButton 来完成。禁用 CheckButtons 改进了 user-friendlyness,因为它为用户提供了一个视觉线索,即无法检查更多按钮。如果我们不禁用 CheckButton,用户可能会感到困惑,为什么当他尝试单击 CheckButton 时没有任何反应。
为实现此功能,我们必须为每个 CheckButton 连接一个回调函数。回调函数计算有多少按钮被选中,并相应地禁用或启用其他按钮。
我们要做的第一件事就是重写__init__
方法。 Checkbar
需要一个新参数,可以同时检查多少个 Checkbutton。我们还必须将回调函数连接到每个 CheckButton。我使用 functools.partial
将复选按钮的变量绑定到回调函数。
def __init__(self, parent=None, picks=[], maxselect=1, side=tk.LEFT,
anchor=tk.W):
super().__init__(parent)
self.maxselect = maxselect
# store all variables and checkbuttons; the callback function
# needs access to them
self._vars = []
self._checkbuttons = []
for pick in picks:
var = tk.IntVar()
# bind the callback function to each checkbutton
chk = tk.Checkbutton(self, text=pick, variable=var,
command=partial(self._var_toggled, var))
chk.pack(side=side, anchor=anchor, expand=tk.YES)
self._vars.append(var)
self._checkbuttons.append(chk)
现在剩下的就是实现回调函数了。它只需要计算有多少复选按钮被选中,并相应地启用或禁用它们:
def _var_toggled(self, var):
# count how many checkbuttons are checked
num = sum(v.get() for v in self._vars)
if num == self.maxselect:
# if we're at maxselect, disable all unchecked checkbuttons
for var, chk in zip(self._vars, self._checkbuttons):
if not var.get():
chk['state'] = tk.DISABLED
else:
# otherwise, re-enable all checkbuttons
for chk in self._checkbuttons:
chk['state'] = tk.NORMAL
(var
参数来自我们之前使用的functools.partial
。)
完整代码:
from functools import partial
import tkinter as tk
class Checkbar(tk.Frame):
def __init__(self, parent=None, picks=[], maxselect=1, side=tk.LEFT,
anchor=tk.W):
super().__init__(parent)
self.maxselect = maxselect
# store all variables and checkbuttons; the callback function
# needs access to them
self._vars = []
self._checkbuttons = []
for pick in picks:
var = tk.IntVar()
# bind the callback function to each checkbutton
chk = tk.Checkbutton(self, text=pick, variable=var,
command=partial(self._var_toggled, var))
chk.pack(side=side, anchor=anchor, expand=tk.YES)
self._vars.append(var)
self._checkbuttons.append(chk)
def _var_toggled(self, var):
# count how many checkbuttons are checked
num = sum(v.get() for v in self._vars)
if num == self.maxselect:
# if we're at maxselect, disable all unchecked checkbuttons
for var, chk in zip(self._vars, self._checkbuttons):
if not var.get():
chk['state'] = tk.DISABLED
else:
# otherwise, re-enable all checkbuttons
for chk in self._checkbuttons:
chk['state'] = tk.NORMAL
我个人会使用单个列表列表。
我可以将 Checkbutton()
和相应的 IntVar()
分配给列表中的列表。
这将允许我检查每个索引的 IntVar() 状态并相应地锁定或解锁检查按钮。
看看下面的代码,如果您有任何问题,请告诉我。
from tkinter import *
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.vars = []
for pick in picks:
var = IntVar()
# appending self.vars with a list of 2 objects at each index.
self.vars.append([Checkbutton(self, text=pick, command=self.check_count, variable = var), var])
self.vars[pick][0].grid(row=0, column=pick)
self.vars[pick][0].bind("<Configure>")
# each time a Checkbutton is selected this method runs.
def check_count(self):
counter = 0
# if the Checkbutton being looked at is check it will add a counter
for cbtn in self.vars:
if cbtn[1].get() == 1:
counter += 1
# if the counter reaches 3 then all Checkbuttons not selected will grey out.
if counter == 3:
for cbtn in self.vars:
if cbtn[1].get() != 1:
cbtn[0].config(state="disabled")
# if counter not 3 then all Checkbuttons are normal.
else:
for cbtn in self.vars:
cbtn[0].config(state="normal")
if __name__ == "__main__":
root = Tk()
Checkbar(root, range(10)).pack(fill=BOTH)
root.mainloop()
我在 Tkinter 中制作了一个带有很多项目的检查栏,但我希望用户只能选择等于或少于一定数量的项目。这是我当前的代码:
from tkinter import *
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.vars = []
for pick in picks:
var = IntVar()
chk = Checkbutton(self, text=pick, variable=var)
chk.pack(side=side, anchor=anchor, expand=YES)
self.vars.append(var)
def state(self):
return [var.get() for var in self.vars]
root = Tk()
lng = Checkbar(root, range(10))
lng.pack(side=TOP, fill=BOTH)
root.mainloop()
检查栏需要检查按钮的最大数量和当前数量的属性。然后,您需要一个每次单击复选按钮时都会调用的命令。在 变量更改后 调用不带参数的命令。
如果可能,应发布不依赖于外部文件的代码。在这种情况下,只需传递一个字符串列表。 (我在 Aran-Fey 的编辑之前复制了。)
from tkinter import *
def checkmax(bar, var):
# called after the intvar is changed
def _check():
print(bar.numpicks, var.get())
if var.get(): # checked
if bar.numpicks < bar.maxpicks:
bar.numpicks += 1
else:
var.set(0)
else: # unchecked
bar.numpicks -= 1
return _check
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], maxpicks=2, side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.maxpicks = maxpicks
self.numpicks = 0
self.vars = []
for pick in picks:
var = IntVar()
chk = Checkbutton(self, text=pick, variable=var,
command=checkmax(self, var))
chk.pack(side=side, anchor=anchor, expand=YES)
self.vars.append(var)
def state(self):
return map((lambda var: var.get()), self.vars)
if __name__ == '__main__':
root = Tk()
lng = Checkbar(root, ['a', 'b', 'c', 'd'], 2)
lng.pack(side=TOP, fill=BOTH)
lng.config(relief=GROOVE, bd=2)
def allstates():
print( list(lng.state() ) )
Button(root, text = 'Quit', command = root.quit).pack(side = RIGHT)
Button(root, text = 'submit', command = allstates).pack(side = RIGHT)
root.mainloop()
您应该添加一个标签,说明可以检查的最大数量。
添加注释:当 Python IntVar 作为 Checkbutton 变量传递时,它被没有 .get 和 .set 方法的 _tkinter.Tcl_Obj 替换。因此该命令需要引用 IntVar 实例,因为 chk['variable'].get 不起作用。
这可以通过在选中最大数量的 CheckButton 时禁用所有未选中的 CheckButton 来完成。禁用 CheckButtons 改进了 user-friendlyness,因为它为用户提供了一个视觉线索,即无法检查更多按钮。如果我们不禁用 CheckButton,用户可能会感到困惑,为什么当他尝试单击 CheckButton 时没有任何反应。
为实现此功能,我们必须为每个 CheckButton 连接一个回调函数。回调函数计算有多少按钮被选中,并相应地禁用或启用其他按钮。
我们要做的第一件事就是重写__init__
方法。 Checkbar
需要一个新参数,可以同时检查多少个 Checkbutton。我们还必须将回调函数连接到每个 CheckButton。我使用 functools.partial
将复选按钮的变量绑定到回调函数。
def __init__(self, parent=None, picks=[], maxselect=1, side=tk.LEFT,
anchor=tk.W):
super().__init__(parent)
self.maxselect = maxselect
# store all variables and checkbuttons; the callback function
# needs access to them
self._vars = []
self._checkbuttons = []
for pick in picks:
var = tk.IntVar()
# bind the callback function to each checkbutton
chk = tk.Checkbutton(self, text=pick, variable=var,
command=partial(self._var_toggled, var))
chk.pack(side=side, anchor=anchor, expand=tk.YES)
self._vars.append(var)
self._checkbuttons.append(chk)
现在剩下的就是实现回调函数了。它只需要计算有多少复选按钮被选中,并相应地启用或禁用它们:
def _var_toggled(self, var):
# count how many checkbuttons are checked
num = sum(v.get() for v in self._vars)
if num == self.maxselect:
# if we're at maxselect, disable all unchecked checkbuttons
for var, chk in zip(self._vars, self._checkbuttons):
if not var.get():
chk['state'] = tk.DISABLED
else:
# otherwise, re-enable all checkbuttons
for chk in self._checkbuttons:
chk['state'] = tk.NORMAL
(var
参数来自我们之前使用的functools.partial
。)
完整代码:
from functools import partial
import tkinter as tk
class Checkbar(tk.Frame):
def __init__(self, parent=None, picks=[], maxselect=1, side=tk.LEFT,
anchor=tk.W):
super().__init__(parent)
self.maxselect = maxselect
# store all variables and checkbuttons; the callback function
# needs access to them
self._vars = []
self._checkbuttons = []
for pick in picks:
var = tk.IntVar()
# bind the callback function to each checkbutton
chk = tk.Checkbutton(self, text=pick, variable=var,
command=partial(self._var_toggled, var))
chk.pack(side=side, anchor=anchor, expand=tk.YES)
self._vars.append(var)
self._checkbuttons.append(chk)
def _var_toggled(self, var):
# count how many checkbuttons are checked
num = sum(v.get() for v in self._vars)
if num == self.maxselect:
# if we're at maxselect, disable all unchecked checkbuttons
for var, chk in zip(self._vars, self._checkbuttons):
if not var.get():
chk['state'] = tk.DISABLED
else:
# otherwise, re-enable all checkbuttons
for chk in self._checkbuttons:
chk['state'] = tk.NORMAL
我个人会使用单个列表列表。
我可以将 Checkbutton()
和相应的 IntVar()
分配给列表中的列表。
这将允许我检查每个索引的 IntVar() 状态并相应地锁定或解锁检查按钮。
看看下面的代码,如果您有任何问题,请告诉我。
from tkinter import *
class Checkbar(Frame):
def __init__(self, parent=None, picks=[], side=LEFT, anchor=W):
Frame.__init__(self, parent)
self.vars = []
for pick in picks:
var = IntVar()
# appending self.vars with a list of 2 objects at each index.
self.vars.append([Checkbutton(self, text=pick, command=self.check_count, variable = var), var])
self.vars[pick][0].grid(row=0, column=pick)
self.vars[pick][0].bind("<Configure>")
# each time a Checkbutton is selected this method runs.
def check_count(self):
counter = 0
# if the Checkbutton being looked at is check it will add a counter
for cbtn in self.vars:
if cbtn[1].get() == 1:
counter += 1
# if the counter reaches 3 then all Checkbuttons not selected will grey out.
if counter == 3:
for cbtn in self.vars:
if cbtn[1].get() != 1:
cbtn[0].config(state="disabled")
# if counter not 3 then all Checkbuttons are normal.
else:
for cbtn in self.vars:
cbtn[0].config(state="normal")
if __name__ == "__main__":
root = Tk()
Checkbar(root, range(10)).pack(fill=BOTH)
root.mainloop()