0

I have created a generic class function for creating radio buttons using python tkinter. The following class code works fine:

import tkinter as tk

class MyGui:

    def __init__(self):  
    
        self.root = tk.Tk()

    def makeRadioButtons(self, list_choices, parent, on_select_function = None, **style_arguments):
        """ The on_select_fuction is what to do once a choice is made """
        
        self.radio_selection = tk.IntVar() # Use "self" or they'll all show as selected on hover
            
        use_value = 1 # start at 1, not index, since IntVar starts with 0
                      # Otherwise, the first button will be selected (since
                      # its value --- 0 --- will match IntVar)
        
        for choice in list_choices:
                
            chk = tk.Radiobutton(parent, 
                                 text = choice, 
                                 variable = self.radio_selection,
                                 value = use_value,
                                 command = on_select_function,
                                 **style_arguments)
            
            chk.pack()
            
            use_value += 1

        return self.radio_selection

    def start(self):
        
        self.root.mainloop()
        
    def stop(self):
        
        self.root.quit()
        self.root.destroy()

I make the radio buttons in a different file using the following code, storing the value of the selected button so that when the selection changes, I can print the value of the new selection:

gui = MyGui()

selected_value = gui.makeRadioButtons([
        "Apple",
        "Banana",
        "Carrot",
        "Dragonfruit"
    ],
    on_select_function = lambda: print(selected_value.get()),
    parent = gui.root)

The issue is that right now I can only print the selected button's value (in this case, a number) and I want to be able to print the text label. I know I could use StringVar to just store the text as the value, but that feels redundant to me, especially if (unlike in my example above) the radio text is long, not short.

I'm sure I could store the list of choices and then use the value to index into it, but I want to avoid that because technically the two pieces of code are separate and unaware of each other --- that is to say, the code that constructs the radio buttons shouldn't know how the buttons are internally implemented, and so it shouldn't assume a relationship between value and an index.

Is there a way to get the text label of a selected radio button, not just the value?

Elliptica
  • 3,928
  • 3
  • 37
  • 68

2 Answers2

1

You can simply pass the text of the radiobutton to the callback on_select_function:

class MyGui:
    ...
    def makeRadioButtons(...):
        ...
        for choice in list_choices:
               
            chk = tk.Radiobutton(parent, 
                                 text = choice, 
                                 variable = self.radio_selection,
                                 value = use_value,
                                 command = lambda v=choice: on_select_function(v),
                                 **style_arguments)
        ...

...
selected_value = gui.makeRadioButtons([
        "Apple",
        "Banana",
        "Carrot",
        "Dragonfruit"
    ],
    on_select_function = lambda v: print(selected_value.get(), v),
    parent = gui.root)
acw1668
  • 40,144
  • 5
  • 22
  • 34
  • This looks promising. It does mean though that my `on_select_function` has to know to expect an input, so if I defined a more complex command function, it will always need to accept a parameter. I think that could be okay if I use lambdas, something like `on_select_function = lambda selected_text: my_normal_function()` because then it's up to that `my_normal_function` whether to use the passed input or not. Thanks! – Elliptica Jul 19 '21 at 08:27
0

Look at this example:

It creates a range of radio buttons using for loop and appends it to a list. So when it is clicked it will get the text of the button in the list index -

from tkinter import *

root = Tk()
variable = IntVar()
variable.set(None)

def gettext(a):
    print(radiobutton_lists[a]['text']) # or you could use .cget()

radiobutton_lists = []

for i in range(6):
    rb = Radiobutton(root,text=i,command=lambda i=i:gettext(i),variable=variable,value=i)
    rb.pack()
    rb.deselect()
    radiobutton_lists.append(rb)

I think this is what you want.

PCM
  • 2,881
  • 2
  • 8
  • 30
  • Thank you for your example. It presents two issues for me currently. The first is that the class needs to be separate from the creation code. Basically, the class can be thought of as a library and the creation code a normal script file. The behavior the example shows only works if the script controls both creation and definition. Second, the example overwrites the command I pass in. That works if all I want is to gettext always, but it's not. I need to pass in different commands depending on need. The `print` command above is just an example. – Elliptica Jul 19 '21 at 08:20