2015-07-14 2 views
4

Мне было интересно, есть ли простой способ создать сетку флажков с помощью Tkinter. Я пытаюсь сделать сетку из 10 строк и столбцов (так 100 флажков), чтобы в каждой строке можно было выбрать только два флажка.Python Tkinter Grid Флажок

Edit: Я использую 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() 

Я пытаюсь использовать состояние = «Disabled» серым из строки сразу две галочки были выбраны.

+2

Итак, покажите нам, что вы пробовали до сих пор! (Также расскажите, какую версию Tkinter и какую версию Python вы используете). Что вы хотите, когда пользователь выбирает третий ящик в данной строке? Вы хотите, чтобы новый ящик отказался от выбора? Или вы хотите отменить выбор одного из выбранных в данный момент полей, и если да, то какой? –

+0

Я отредактировал свой пример кода, чтобы показать, как вы могли бы это сделать, используя то, что вы уже предоставили. – maccartm

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

Спасибо! Вы сказали, что в вашем примере IntVars определяют значение Checkbutton. Есть ли способ использовать их для вывода списка выбранных кнопок. Например, если в строке 1 были выбраны столбцы 1 и 3, в строке 2 были выбраны столбцы 1 и 9, а в строке 3 был выбран только столбец 3, список будет выглядеть как [(1,3), (1,9) ]. Какие-либо предложения? –

+0

Вам нужны только строки, в которых есть 2 элемента? – maccartm

+0

Да, всего 2 элемента. –

1

Вот версия, которая помещает все в класс, поэтому нам не нужно использовать глобальные переменные. Он также избегает построения 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() 
Смежные вопросы