如何在 python tkinter 中的动态小部件之间应用相同的更改?

问题描述

我有以下代码来创建动态复选框,具体取决于数据库中保存了多少来自某个位置的橄榄球运动员:

#Dynamic CheckBoxes
connectDB = sqlite3.connect("H:\\Python\\Uned_5\\Databases\\CDRR.db")
Cursor = connectDB.cursor()
Cursor.execute("SELECT firstName,surname FROM firstTeam WHERE position = 'Prop'")
nameResult = Cursor.fetchall()

for j in range(len(nameResult)):
    theText = nameResult[j]
    propCheckbutton = Checkbutton(framePropCheck,text = theText,bg = theBlue,fg = theWhite,font = ("calibri",13),state = disABLED)
    propCheckbutton.grid(row = 0,column = j)

重复此代码,为每个橄榄球位置创建动态复选框。

当您点击与玩家位置关联的按钮时,它会运行一个功能,禁用除您点击的位置之外的所有复选框(将其视为过滤玩家位置的按钮)。例如,如果我按下“道具”按钮,除了包含在道具位置上比赛的球员的复选框之外,所有其他复选框都将被禁用。

这是与按钮相关的代码

propButton = Button(framePosition,text = "Props",bg = theGray,command = selectProps)
propButton.grid(row = 0,column = 0)

这是它导致的功能

def selectProps():    
    try:
        propCheckbutton.config(state = norMAL)
        hookerCheckbutton.config(state = disABLED)
        lockCheckbutton.config(state = disABLED)
        wingerCheckbutton.config(state = disABLED)
        scrumCheckbutton.config(state = disABLED)
        flyCheckbutton.config(state = disABLED)
        centreCheckbutton.config(state = disABLED)
        fullCheckbutton.config(state = disABLED)
    except NameError:
        pass

数据库中存储的每个位置只有 1 个球员时,一切正常,但是一旦将第二个球员添加到与现有球员相同的位置,.config 仅适用于最新的动态复选框。 例如,如果我有 2 个玩家在道具位置,第一个道具仍然会跟随:

propCheckbutton = Checkbutton(framePropCheck,state = disABLED)

而第二个道具将跟随:

propCheckbutton.config(state = norMAL)

有没有办法让 propCheckbutton.config(state = norMAL) 应用于所有动态复选框?

以下是最小的、可重现的示例,应该适用于想要查看该问题的其他人:

from tkinter import *
import sqlite3
import sys
import os
pathname = os.path.dirname(sys.argv[0])

#This function only applies this propCheckbutton.config to the latest checkBox created 
def selectProps():    
    try:
        propCheckbutton.config(state = norMAL)
        hookerCheckbutton.config(state = disABLED)
    except NameError:
        pass

def selectHookers():
    try:
        propCheckbutton.config(state = disABLED)
        hookerCheckbutton.config(state = norMAL)
    except NameError:
        pass

#Creating a basic tkinter window
Window = Tk()
Window.geometry("700x700")

#Creating the table in database
connectDB = sqlite3.connect(pathname + "\\CDRR.db")
Cursor = connectDB.cursor()
Cursor.execute(
    """CREATE TABLE IF NOT EXISTS firstTeam(
        firstName text,surname text,position text
        )""")

#Inserting the data quickly and making sure the same data isn't inserted twice
normalText = str.maketrans("(),'[]",6*" ")
insertValues = ("INSERT INTO firstTeam (firstName,surname,position) VALUES (?,?,?)")
selectValues = ("SELECT firstName FROM firstTeam WHERE firstName = ?")
Cursor.execute(selectValues,[("Johnny")])
prop_1 = Cursor.fetchall()
prop_1 = str(prop_1)
prop_1.translate(normalText)
prop_1 = prop_1.strip()
if "Johnny" not in prop_1:
    Cursor.execute(insertValues,[("Johnny"),("Silverhand"),("Prop")])
else:
    pass

Cursor.execute(selectValues,[("Jackie")])
prop_2 = Cursor.fetchall()
prop_2 = str(prop_2)
prop_2.translate(normalText)
prop_2 = prop_2.strip()
if "Jackie" not in prop_2:
    Cursor.execute(insertValues,[("Jackie"),("Welles"),[("Dexter")])
hooker_1 = Cursor.fetchall()
hooker_1 = str(hooker_1)
hooker_1.translate(normalText)
hooker_1 = hooker_1.strip()
if "Dexter" not in hooker_1:
    Cursor.execute(insertValues,[("Dexter"),("DeShawn"),("Hooker")])
else:
    pass

connectDB.commit()

#Buttons
propButton = Button(Window,column = 0)

hookerButton = Button(Window,text = "Hookers",command = selectHookers)
hookerButton.grid(row = 0,column = 1)

#Dynamic CheckBoxes
Cursor.execute("SELECT firstName,surname FROM firstTeam WHERE position = 'Prop'")
nameResult = Cursor.fetchall()

for j in range(len(nameResult)):
    theText = nameResult[j]
    propCheckbutton = Checkbutton(Window,state = disABLED)
    propCheckbutton.grid(row = 1,column = j)

Cursor.execute("SELECT firstName,surname FROM firstTeam WHERE position = 'Hooker'")
nameResult = Cursor.fetchall()

for j in range(len(nameResult)):
    theRow = 0
    theText = nameResult[j]
    hookerCheckbutton = Checkbutton(Window,state = disABLED)
    hookerCheckbutton.grid(row = 2,column = j)

Window.mainloop()

感谢您的任何建议。

解决方法

您需要使用 dictionary 将那些 Checkbutton 小部件组存储为 position,然后您可以轻松启用/禁用您想要的:

# enable the checkbuttons with given position
def select_position(position):
    for pos,players in buttons.items():
        for player in players:
            player.config(state=NORMAL if pos == position else DISABLED)

#Buttons
propButton = Button(Window,text="Props",command=lambda: select_position("Prop"))
propButton.grid(row=0,column=0)

hookerButton = Button(Window,text="Hookers",command=lambda: select_position("Hooker"))
hookerButton.grid(row=0,column=1)

buttons = {} # store the checkbuttons group by position

#Dynamic Checkboxes
for i,position in enumerate(["Prop","Hooker"]):
    Cursor.execute("SELECT firstName,surname FROM firstTeam WHERE position = ?",(position,))
    nameResult = Cursor.fetchall()

    buttons[position] = []
    for j,theText in enumerate(nameResult):
        cb = Checkbutton(Window,text=theText,state=DISABLED)
        cb.grid(row=i+1,column=j)
        buttons[position].append(cb)