Tkinter - Создание нескольких флажков с помощью цикла - PullRequest
2 голосов
/ 06 октября 2019

Я пытаюсь создать программу, которая позволяет пользователю выбрать любое количество флажков и нажать кнопку, чтобы вернуть случайный результат из этих флажков. Поскольку я основываю свой список на списке окончательных версий Smash bros, я стараюсь избегать создания более 70 переменных, чтобы просто поставить флажки. Однако я не могу понять, как это повторить. Различные значения, заданные для строк, являются просто заполнителями, пока я не смогу это выяснить. Я также хотел бы иметь кнопку сброса в верхней части, которая позволяет пользователю автоматически снимать все флажки. Этот код - то, что я имею до сих пор. Любая помощь будет принята с благодарностью.

#!/usr/bin/python3

from tkinter import *
window = Tk()

#window name and header
window.title("Custom Random SSBU")
lbl = Label(window, text="Select the fighters you would like to include:")
lbl.grid(column=1, row=0)

f = [] #check boxes

ft = open("Fighters.txt").readlines() #list of all the character names

fv=[0]*78 #list for tracking what boxes are checked

ff=[] #list to place final character strings

def  reset():
   for i in fv:
       fv[i]=0

rst = Button(window, text="Reset", command=reset)
rst.grid(column=0, row=3)

for y in range (0,77):
    f[y] = Checkbutton(window, text = ft[y], variable = fv[y])
    f[y].grid(column=0, row=4+y)

def done():
    for j in fv:
        if fv[j] == 1:
            ff.append(fv[j])
    result = random.choice(ff)
    r=Label(window, text=result)

d = Button(window, text="Done", command=done)
d.grid(column=0, row = 80)

window.mainloop()

Ответы [ 2 ]

1 голос
/ 06 октября 2019

К сожалению, я боюсь, что придется создавать переменные для каждого флажка.

tkinter имеет специальное назначение Классы переменных для хранения различных типовзначений, и если вы указываете экземпляр одного в качестве опции variable= при создании виджетов, таких как Checkbutton, он будет автоматически устанавливать или сбрасывать свое значение всякий раз, когда пользователь изменяет его, поэтому все, что ваша программа должна сделать, это проверить еготекущее значение путем вызова его get() метода.

Вот пример изменений в вашем коде, необходимых для их создания в цикле (и использования их в функции обратного вызова done()):

import random
from tkinter import *

window = Tk()

#window name and header
window.title("Custom Random SSBU")

lbl = Label(window, text="Select the fighters you would like to include:")
lbl.grid(column=1, row=0)

f = [] # Check boxes.

with open("Fighters.txt") as fighters:
    ft = fighters.read().splitlines() # List of all the character names.

fv = [BooleanVar(value=False) for _ in ft] # List to track which boxes are checked.

ff = [] # List to place final character strings.

def  reset():
   for var in fv:
       var.set(False)

rst = Button(window, text="Reset", command=reset)
rst.grid(column=0, row=3)

for i, (name, var) in enumerate(zip(ft, fv)):
    chk_btn = Checkbutton(window, text=name, variable=var)
    chk_btn.grid(column=0, row=i+4, sticky=W)

def done():
    global ff
    ff = [name for name, var in zip(ft, fv) if var.get()]  # List of checked names.
    # Randomly select one of them.
    choice.configure(text=random.choice(ff) if ff else "None")

d = Button(window, text="Done", command=done)
d.grid(column=0, row=len(ft)+4)

choice = Label(window, text="None")
choice.grid(column=1, row=3)

window.mainloop()

Я не был уверен, куда вы хотите, чтобы Label содержал результат, поэтому я просто поместил его справа от кнопки Сброс .

1 голос
/ 06 октября 2019
variable = fv[y]

Это ищет значение fv[y] - то есть целое число 0 - во время создания Checkbutton и использует его для аргумента variable.

Вам нужновместо этого использовать экземпляр одного из классов отслеживания значений, предоставляемых TKinter . В этом случае мы хотим BooleanVar, так как мы отслеживаем логическое состояние. Мы все еще можем создать их в списке заранее:

text = open("Fighters.txt").readlines()
# Let's not hard-code the number of lines - we'll find it out automatically,
# and just make one for each line.
trackers = [BooleanVar() for line in text]
# And we'll iterate over those pair-wise to make the buttons:
buttons = [
    Checkbutton(window, text = line, variable = tracker)
    for line, tracker in zip(text, trackers)
]

(но мы можем не сделать, например trackers = [BooleanVar()] * len(text), потому что это дает нам то же самое трекер 78 раз, и, таким образом, каждый флажок будет использовать этот трекер, мы должны отслеживать каждый отдельно.)

Когда вы установите этот флажок, TKinter автоматически обновит внутреннее состояние соответствующего BooleanVar(), чтомы можем проверить, используя .get() метод. Кроме того, когда мы устанавливаем наши параметры для random.choice, мы хотим выбрать соответствующий текст для кнопки, а не трекер. Мы можем сделать это снова с помощью трюка zip.

Итак, мы хотим что-то более похожее на:

result_label = Label(window) # create it ahead of time

def done():
    result_label.text = random.choice(
        label
        for label, tracker in zip(text, trackers)
        if tracker.get()
    )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...