简体   繁体   中英

Checkbutton does not work in tkinter python - Tkinter, checkbuttons, python

I use tkinter as an interface to update dataframe. I did not want to use treeview because I liked using grid better. If you toggle the checkbutton it changes its value accordingly (0 - not selected, 1 - selected) In order to get the values for df I use variables for every checkbutton that correspond with their position in the df ex: var02 is df.iloc[0,2] However for some reason buttons column = AG and rows = 11,21,31 do not work, they only work if I create them separately, not in the for loop. I cannot understand what is the problem with buttons column = AG and rows = 11,21,31 and why I can't get values if I create them in a loop.

# update values in the df with saved variables
def update_vals():
    for i in range(0,len(df.columns)):
        for j in range(0,len(df.index)):
            if pd.isna(df.iloc[j,i]) == False:  
                var = f"""df.iloc[j,i] = var{j}{i}.get()"""
                exec(var)
               
                
#select all                
def select_all():
    for i in variables:
        var=f"{i}.set(value=1)"
        exec(var)
    
def deselect_all():
    for i in variables:
        var=f"{i}.set(value=0)"
        exec(var)

#create test df
df = pd.DataFrame(np.random.randint(0,1,size=(33, 20)), columns=list('ABCDEFGHIGKLMPOPQRST'))
cols = df.columns 
variables = []

#open window
top = Tk()  

#create columns and index in the grid
for i in range(0,len(df.columns)):
    tk.Label(top, text = df.columns[i]).grid(row = 0, column = i+1)
for i in range(0,len(df.index)):
    tk.Label(top, text = i).grid(row = i+1, column = 0)

#create checkbuttons in the grid and assign values to checkbutton variables
for i in range(0,len(df.columns)):
    for j in range(0,len(df.index)):
        if pd.isna(df.iloc[j,i]) == False:
            #var_str =f"global var{j}{i}"
            #exec(var_str)
            
            var_str=f"var{j}{i}=tk.IntVar(top)"
            exec(var_str)
            
            variables.append(f"var{j}{i}")
            
            var_str=f"""Checkbutton(top, variable=var{j}{i}, onvalue = 1).grid(row = {j+1}, column = {i+1})"""
            exec(var_str)
           
        
tk.Button(top, text="Update all", state=NORMAL, command=update_vals,bg="#C2CDD1").grid(column = 40, row = 32, sticky="ew")
tk.Button(top, text="Select all", state=NORMAL, command=select_all,bg="#C2CDD1").grid(column = 40, row = 5, sticky="ew")
tk.Button(top, text="Deselect all", state=NORMAL, command=deselect_all,bg="#C2CDD1").grid(column = 40, row = 6, sticky="ew")

top.mainloop()

The error comes from the fact that some variable names are the same. In your example: var112 can be the variable associated to the first row, 12th column, but it's also 11th row, 2nd column.

Generally, creating variables like you are doing is very bad practice. (also using exec makes your code unsafe and harder to debug). You should put your variables in an appropriate structure. A numpy array for example:

import pandas as pd
import tkinter as tk
import numpy as np

# update values in the df with saved variables
def update_vals():
    for i in range(0,len(df.columns)):
        for j in range(0,len(df.index)):
            if pd.isna(df.iloc[j,i]) == False:  
                df.iloc[j,i] = variables[j][i].get()
                           
#select all                
def select_all():
    for row in variables:
        for el in row:
            el.set(value=1)
    
def deselect_all():
    for row in variables:
        for el in row:
            el.set(value=0)

#create test df
df = pd.DataFrame(np.random.randint(0,1,size=(33, 20)), columns=list('ABCDEFGHIGKLMPOPQRST'))
cols = df.columns 

#open window
top = tk.Tk()  

variables = np.array([[tk.IntVar(top)]*len(df.columns)]*len(df.index))

#create columns and index in the grid
for i in range(0,len(df.columns)):
    tk.Label(top, text = df.columns[i]).grid(row = 0, column = i+1)
for i in range(0,len(df.index)):
    tk.Label(top, text = i).grid(row = i+1, column = 0)

#create checkbuttons in the grid and assign values to checkbutton variables
for i in range(0,len(df.columns)):
    for j in range(0,len(df.index)):
        if pd.isna(df.iloc[j,i]) == False:  
            tk.Checkbutton(top, variable=variables[j, i], onvalue = 1).grid(row = j+1, column = i+1)
 
tk.Button(top, text="Update all", state="normal", command=update_vals,bg="#C2CDD1").grid(column = 40, row = 32, sticky="ew")
tk.Button(top, text="Select all", state="normal", command=select_all,bg="#C2CDD1").grid(column = 40, row = 5, sticky="ew")
tk.Button(top, text="Deselect all", state="normal", command=deselect_all,bg="#C2CDD1").grid(column = 40, row = 6, sticky="ew")

top.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM