Python Tkinter网格复选框

时间:2015-07-14 15:16:34

标签: python checkbox tkinter grid

我想知道是否有一种使用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()

我试图使用州='已禁用'一旦选中了两个复选框,就会灰显一行。

2 个答案:

答案 0 :(得分:3)

以下是使用您提供的10x10网格的示例。它应该为您提供如何实现它的基本概念。

请确保您对每个Checkbutton(示例中的boxes)以及示例中的每个IntVarboxVars)保持引用。

这就是原因:

- 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()