'How do I call the same function with tkinter?

I have a simple tkinter window with two radiobuttons. If I select 'Yes', a new line is added with two other radiobuttons. I try to use the same function every time I click 'Yes' but the radiobuttons are automatically selected if the mouse is moved onto them.

Here's my code:

from tkinter import *
import tkinter as tk

class Application(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.i = 1

        self.Frame1 = Frame(self)
        self.Frame1.grid(row=0, column=0)

        self.label = tk.Label(self.Frame1, text='Select Yes or No')
        self.label.grid(row=0, column=0)

        self.radioValueYesOrNo = tk.IntVar()
        self.RadiobuttonYesOrNo = tk.Radiobutton(self.Frame1, text='Yes',
                                                            variable=self.radioValueYesOrNo,
                                                            value=1,
                                                            command=self.addWidgets
                                                            )
        self.RadiobuttonYesOrNo.grid(row=0, column=1)
        
        self.RadiobuttonNonBoostPresent = tk.Radiobutton(self.Frame1, text='No',
                                                            variable=self.radioValueYesOrNo,
                                                            value=2)
        self.RadiobuttonNonBoostPresent.grid(row=0, column=2, padx=20)

    def addWidgets(self):
        valueRadioButton = self.returnValueRadiobutton()
        if valueRadioButton == 1:
            self.label = tk.Label(self.Frame1, text='Select Yes or No')
            self.label.grid(row=self.i, column=0)

            self.radioValueYesOrNo = tk.IntVar()
            self.RadiobuttonYesOrNo = tk.Radiobutton(self.Frame1, text='Yes',
                                                                variable=self.radioValueYesOrNo,
                                                                value=1,
                                                                command=self.addWidgets
                                                                )
            self.RadiobuttonYesOrNo.grid(row=self.i, column=1)
            self.RadiobuttonNonBoostPresent = tk.Radiobutton(self.Frame1, text='No',
                                                                variable=self.radioValueYesOrNo,
                                                                value=2)
            self.RadiobuttonNonBoostPresent.grid(row=self.i, column=2, padx=20)
            self.i = self.i+1

    def returnValueRadiobutton(self):
        return self.radioValueYesOrNo.get()

if __name__ == "__main__":
    app = Application()
    app.mainloop()

Does someone know how to fix this? Is this the best way to write the code?



Solution 1:[1]

Youre not too far off, however you would need to move your overwriting of self.i up so your .grid calls already use the updated value (edit: i was wrong, you use 0 initially and set i to 1, so this should be no issue). In general i advise you to use a list, dict or some kind where you store your widgets so you can access them later on. I think in your example you keep overwriting the same variables which is why it was messed up. I modified your code and added two optional parts where you delete the callbacks from checkboxes who already produced a new pair, or to even disable the old ones. However, i hope my solution is clear and helps you get going:

from tkinter import *
import tkinter as tk
from functools import partial


class Application(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        self.i = 1

        self.Frame1 = Frame(self)
        self.Frame1.grid(row=0, column=0)

        self.label = tk.Label(self.Frame1, text='Select Yes or No')
        self.label.grid(row=0, column=0)

        self.values = []
        self.radiobuttons_yes = []
        self.radiobuttons_no = []

        self.add_radiobuttons()  # adds the first pair

    def add_radiobuttons(self):
        """Adds a new set of radiobuttons and appends radiobutton_callback with the current index as command"""
        self.values.append(tk.IntVar())
        self.radiobuttons_yes.append(tk.Radiobutton(self.Frame1, text='Yes',
                                                    variable=self.values[-1],
                                                    value=1,
                                                    command=partial(self.radiobutton_callback, len(self.values) - 1)))
        self.radiobuttons_yes[-1].grid(row=self.i, column=0)
        self.radiobuttons_no.append(tk.Radiobutton(self.Frame1, text='No',
                                                   variable=self.values[-1],
                                                   value=2,
                                                   command=partial(self.radiobutton_callback, len(self.values) - 1)))
        self.radiobuttons_no[-1].grid(row=self.i, column=1)
        self.i += 1

    def radiobutton_callback(self, index):
        """Callback function for the radiobuttons"""
        if self.values[index].get() == 1:
            # optional: delete command of current radiobuttons to prevent multiple calls
            self.radiobuttons_yes[index].config(command='')
            self.radiobuttons_no[index].config(command='')

            # # optional2: set previous radiobuttons to inactivate
            # self.radiobuttons_yes[index].config(state=DISABLED)
            # self.radiobuttons_no[index].config(state=DISABLED)

            # add new radiobuttons
            self.add_radiobuttons()


if __name__ == "__main__":
    app = Application()
    app.mainloop()

Solution 2:[2]

    def addWidgets(self):
        valueRadioButton = self.returnValueRadiobutton()
        if valueRadioButton == 1:
            label = tk.Label(self.Frame1, text='Select Yes or No')
            label.grid(row=self.i, column=0)
            print("creating")
            radioValueYesOrNo = tk.IntVar()
            RadiobuttonYesOrNo = tk.Radiobutton(self.Frame1, text='Yes',
                                                             variable=radioValueYesOrNo,
                                                             value=1,
                                                             command=lambda: self.addWidgets()
                                                             )
            RadiobuttonYesOrNo.grid(row=self.i, column=1)
            RadiobuttonNonBoostPresent = tk.Radiobutton(self.Frame1, text='No',
                                                             variable=radioValueYesOrNo,
                                                             value=2)
            RadiobuttonNonBoostPresent.grid(row=self.i, column=2, padx=20)
            self.i = self.i+1

We want to create a new own button object right? So we can't use the same variable self.radioValueYesOrNo and self.RadiobuttonYesOrNo and self.RadiobuttonNonBoostPresent for different buttons.

Yup, the solution is making their variables, just in the function scope. hope it helps, have fun :)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mnikley
Solution 2 ariamadeus