Home > Software design >  Python/TKinter - How to generate a list of selected widgets by name
Python/TKinter - How to generate a list of selected widgets by name

Time:06-05

I've re-written the question for clarity. I'm open to anything- complete redesign if needed.

I am having a problem and trying to start from the ground up since I can't find any solutions that work.

I have a file with a 75 columns, and each column is a feature. I would like the user to be able to select which features to include in the analysis.

Question 1. What is the best widget to use for this? First, I tried using a listbox, but it wouldn't let me select non-consecutive items except on the default state which required selecting each individual item (there are 75 items so this would be a lot of click).

Next, I tried using checkboxes. I think this is the best solution, but I'm having problems implementing. Here's what the UI looks like: enter image description here

I am trying to associate this with a list of 'clicked' boxes that I can then pass to my back-end to remove unwanted variables since the rest of the application is pretty data intensive.

The select all and deselect all buttons work fine; my problem is with the individual selections.

Is this the right way to accomplish this goal at all? If so, how might this be accomplished? TIA- I started using tkinter yesterday so I know very little.

Here is how I'm generating the below (simplified)

Code that creates the button:

import tkinter as tk

settings.data_included_cols = ['button1'] #This is the list of clicked buttons

checkbox_buttons=dict()
checkbox_variables=dict()

button_names=['button1', 'button2', 'button3']

i=0

for i in range(len(button_names)):
    checkbox_variables[i]=1
    checkbox_button[i] = tk.Checkbutton(frame, text=button_names[i],
                                    variable=checkbox_variables[i],
                                    command=checkbox_click)

Command Code (checkbox_click)- I don't know what goes here but nothing I've tried so far has worked. Originally I was calling it as: command=lambda: checkbox_click(i), and it tried to work like the below:

def checkbox_click(i):
    if i in settings.data_included_cols:
       settings.data_included_cols.remove(button_name[i])

This doesn't work because 'i' is not associated with the button, it's associated with the loop so it will always be whatever the final value is (in this case 3 which maps to button3).

Any thoughts?

CodePudding user response:

The problem is that although you assign each check-button different "feature" as you create them, when one of the buttons is clicked, the program will execute the function

lambda: feature_list(feature)

where it will try to get the value of "feature", and will find that it equal to the last one in the list.

The seemingly only solution is to assign each check-button a variable, such as something like this:

import tkinter as tk
from tkinter import ttk

def click():
    temp = []
    for i in range(3):
        if value[i].get() == 1:
            temp.append(feature[i])
    print(temp)

if __name__ == "__main__":

    root = tk.Tk()

    feature = ["one", "two", "three"]
    check = {}
    value = {}

    for i in range(3):
        value[i] = tk.IntVar(value=0)
        check[i] = ttk.Checkbutton(root, text=feature[i], variable=value[i], onvalue=1, offvalue=0, command=click)
        check[i].grid(row=0, column=i)

    root.mainloop()

then when you select some buttons, for example "one" and "three", then it will print

['one', 'three']

You should not be stingy for creating Tk variables, since the space consumed by a check-button should be much bigger than that consumed by a variable. Also, creating variables to get the state of widgets is the most "standard" and "Pythonic" way which you should always use.

CodePudding user response:

Checkboxes do not need to have a command specified.

They do however need a StringVar or IntVar associated with them, so you can query the values.

So I would build your code like this:

names = {
    "id", "member_id", "loan_amnt"
}

values = {}
boxes = {}

for name in names:
    values[name] = tk.Intvar(value=1)
    boxes = ttk.Checkbox(root, text=name, variable=values[name])

Once the user has made submitted their choice, you can query the dict of values to see which options were selected.

  • Related