我想知道是否有一种使用Tkinter创建复选框网格的简单方法。我正在尝试制作10行和10列的网格(所以100个复选框),这样每行只能选择两个复选框。
编辑:我使用python 2.7和spyder
到目前为止我所拥有的:
from Tkinter import*
master = Tk()
master.title("Select Groups")
rows=10
columns=10
for x in range(rows):
for y in range(columns):
Label(master, text= "Group %s"%(y+1)).grid(row=0,column=y+1)
Label(master, text= "Test %s"%(x+1)).grid(row=x+1,column=0)
Checkbutton(master).grid(row=x+1, column=y+1)
mainloop()
我试图使用州='已禁用'一旦选中了两个复选框,就会灰显一行。
答案 0 :(得分:3)
以下是使用您提供的10x10网格的示例。它应该为您提供如何实现它的基本概念。
请确保您对每个Checkbutton
(示例中的boxes
)以及示例中的每个IntVar
(boxVars
)保持引用。
这就是原因:
- Checkbuttons
需要致电config(state = DISABLED/NORMAL)
。
- IntVars
来确定每个Checkbutton
的值。
除了那些关键元素外,它基本上只是一些2D数组处理。
这是我的示例代码(现在基于您提供的代码)。
from Tkinter import *
master = Tk()
master.title("Select Groups")
rows=10
columns=10
boxes = []
boxVars = []
# Create all IntVars, set to 0
for i in range(rows):
boxVars.append([])
for j in range(columns):
boxVars[i].append(IntVar())
boxVars[i][j].set(0)
def checkRow(i):
global boxVars, boxes
row = boxVars[i]
deselected = []
# Loop through row that was changed, check which items were not selected
# (so that we know which indeces to disable in the event that 2 have been selected)
for j in range(len(row)):
if row[j].get() == 0:
deselected.append(j)
# Check if enough buttons have been selected. If so, disable the deselected indeces,
# Otherwise set all of them to active (in case we have previously disabled them).
if len(deselected) == (len(row) - 2):
for j in deselected:
boxes[i][j].config(state = DISABLED)
else:
for item in boxes[i]:
item.config(state = NORMAL)
def getSelected():
selected = {}
for i in range(len(boxVars)):
temp = []
for j in range(len(boxVars[i])):
if boxVars[i][j].get() == 1:
temp.append(j + 1)
if len(temp) > 1:
selected[i + 1] = temp
print selected
for x in range(rows):
boxes.append([])
for y in range(columns):
Label(master, text= "Group %s"%(y+1)).grid(row=0,column=y+1)
Label(master, text= "Test %s"%(x+1)).grid(row=x+1,column=0)
boxes[x].append(Checkbutton(master, variable = boxVars[x][y], command = lambda x = x: checkRow(x)))
boxes[x][y].grid(row=x+1, column=y+1)
b = Button(master, text = "Get", command = getSelected, width = 10)
b.grid(row = 12, column = 11)
mainloop()
答案 1 :(得分:2)
这是一个将所有内容放入课堂的版本,因此我们不需要使用全局变量。它还避免了import *
构造,这在Python中通常被认为是不好的样式。确实,许多示例代码使用import *
,但这不是一个好习惯,因为它会使用导入模块中的所有名称来混淆全局命名空间。因此,这些名称可能与您自己的变量名称冲突,并且它们也可能与您使用import *
导入的其他模块的名称冲突。
当窗口关闭时,程序会为每个测试行打印所选组的列表。
#!/usr/bin/env python
''' Create a grid of Tkinter Checkbuttons
Each row permits a maximum of two selected buttons
From http://stackoverflow.com/q/31410640/4014959
Written by PM 2Ring 2015.07.15
'''
import Tkinter as tk
class CheckGrid(object):
''' A grid of Checkbuttons '''
def __init__(self, rows=10, columns=10):
master = tk.Tk()
master.title("Select Groups")
rowrange = range(rows)
colrange = range(columns)
#Create the grid labels
for x in colrange:
w = tk.Label(master, text="Group %s" % (x + 1))
w.grid(row=0, column=x+1)
for y in rowrange:
w = tk.Label(master, text="Test %s" % (y + 1))
w.grid(row=y+1, column=0)
#Create the Checkbuttons & save them for future reference
self.grid = []
for y in rowrange:
row = []
for x in colrange:
b = tk.Checkbutton(master)
#Store the button's position and value as attributes
b.pos = (y, x)
b.var = tk.IntVar()
#Create a callback bound to this button
func = lambda w=b: self.check_cb(w)
b.config(variable=b.var, command=func)
b.grid(row=y+1, column=x+1)
row.append(b)
self.grid.append(row)
#Track the number of on buttons in each row
self.rowstate = rows * [0]
master.mainloop()
def check_cb(self, button):
''' Checkbutton callback '''
state = button.var.get()
y, x = button.pos
#Get the row containing this button
row = self.grid[y]
if state == 1:
self.rowstate[y] += 1
if self.rowstate[y] == 2:
#Disable all currently off buttons in this row
for b in row:
if b.var.get() == 0:
b.config(state=tk.DISABLED)
else:
self.rowstate[y] -= 1
if self.rowstate[y] == 1:
#Enable all currently off buttons in this row
for b in row:
if b.var.get() == 0:
b.config(state=tk.NORMAL)
#print y, x, state, self.rowstate[y]
def get_checked(self):
''' Make a list of the selected Groups in each row'''
data = []
for row in self.grid:
data.append([x + 1 for x, b in enumerate(row) if b.var.get()])
return data
def main():
g = CheckGrid(rows=10, columns=10)
#Print selected Groups in each Test row when the window closes
data = g.get_checked()
for y, row in enumerate(data):
print "Test %2d: %s" % (y + 1, row)
if __name__ == '__main__':
main()