2

I have four radio buttons. Underneath these four button is an Entry widget. I am trying to make this Entry widget only become available to type into when the last radio button is selected. The gui is in a class, as you can see in the code below:

class Gui:
    def __init__(self):
        pass

    def draw(self):
        global root

        if not root:
            root  = tk.Tk()
            root.geometry('280x350')

            self.type = tk.StringVar()
            self.type_label = tk.Label(text="Game Mode")
            self.name_entry = tk.Entry()
            self.name_entry.configure(state="disabled")
            self.name_entry.update()
            self.type_entry_one = tk.Radiobutton(text="Garage", value="garage", variable=self.type, command=self.disable_entry(self.name_entry))
            self.type_entry_two = tk.Radiobutton(text="Festival", value="festival", variable=self.type, command=self.disable_entry(self.name_entry))
            self.type_entry_three = tk.Radiobutton(text="Studio", value="studio", variable=self.type, command=self.disable_entry(self.name_entry))
            self.type_entry_four = tk.Radiobutton(text="Rockslam", value="rockslam", variable=self.type, command=self.enable_entry(self.name_entry))
            
         
            self.type_label.pack()
            self.type_entry_one.pack()
            self.type_entry_two.pack()
            self.type_entry_three.pack()
            self.type_entry_four.pack()
            self.name_entry.pack()

            root.mainloop()

    def enable_entry(self, entry):
        entry.configure(state="normal")
        entry.update()

    def disable_entry(self, entry):
        entry.configure(state="disabled")
        entry.update()





if __name__ == '__main__':
    root = None
    gui = Gui()
    gui.draw()

However, the the self.name_entry is always available to type into. What am I doing wrong. If you still don't understand what is happening then please run this code yourself and you will see.

Thank you very much for your time and I look forward to responses.

Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
Lucy
  • 21
  • 5

2 Answers2

1

The only problemS, I see, your facing here is because your not passing in the value "properly" into the function, when you use (..), your calling the function, so to get rid of that use lambda, like:

self.type_entry_one = tk.Radiobutton(text="Garage", value="garage", variable=self.type, command=lambda: self.disable_entry(self.name_entry))
self.type_entry_two = tk.Radiobutton(text="Festival", value="festival", variable=self.type, command=lambda:self.disable_entry(self.name_entry))
self.type_entry_three = tk.Radiobutton(text="Studio", value="studio", variable=self.type, command=lambda:self.disable_entry(self.name_entry))
self.type_entry_four = tk.Radiobutton(text="Rockslam", value="rockslam", variable=self.type, command=lambda:self.enable_entry(self.name_entry))

When using command=lambda:func(arg), this will get executed only when selecting a radiobutton. That is the point of using a radiobutton, right?

Also notice that when the initial code is run, the entire radiobuttons are selected, I think its probably because of tristate values, to get rid of that there are 2 ways I'm aware of:

  1. Changing the declaration of self.type to:
self.type = tk.StringVar(value=' ')
  1. Or, you could also go on adding an extra option to each radiobutton, tristatevalue=' ', like:
self.type_entry_one = tk.Radiobutton(text="Garage",..,tristatevalue=' ')

But make sure to do just one of the above solution. Take a read here about more on tristate values.

Also keep a note that your not passing in any master window to the widgets, its fine as long as your having just one window, when working with multiple windows, it may get confusing for where the widgets should appear.

Also side-note, if this is the complete code, then if nothing is being done on __init__(), its definition can be removed.

Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
1

You have the right idea about using the RadioButton to enable/disable the entry widget. Mostly it is your class design that is flawed - it is halfway between OO code, and procedural code...

I fixed the class structure and made it a subclass of tk.Tk so it completely encapsulate your GUI. The name_entry is now enabled only when type_entry_four radio button is selected, and disabled otherwise. I've set that last button to be selected at launch, but you can easily change that; it results in the entry being enabled at launch.
Superfluous variable passing through methods was removed, as was the draw method and the calls to it; all widget creation is now conveniently found in GUI.__init__

import tkinter as tk


class Gui(tk.Tk):
    def __init__(self):
        super().__init__()
        self.geometry('280x350')

        self.select_type = tk.StringVar()
        self.type_label = tk.Label(self, text='Game Mode')
        self.name_entry = tk.Entry(self)
        self.type_entry_one = tk.Radiobutton(self, text='Garage', value='garage', variable=self.select_type, command=self.disable_entry)
        self.type_entry_two = tk.Radiobutton(self, text='Festival', value='festival', variable=self.select_type, command=self.disable_entry)
        self.type_entry_three = tk.Radiobutton(self, text='Studio', value='studio', variable=self.select_type, command=self.disable_entry)
        self.type_entry_four = tk.Radiobutton(self, text='Rockslam', value='rockslam', variable=self.select_type, command=self.enable_entry)

        self.select_type.set('rockslam')   # select the last radiobutton; also enables name_entry
        
        self.type_label.pack()
        self.type_entry_one.pack()
        self.type_entry_two.pack()
        self.type_entry_three.pack()
        self.type_entry_four.pack()
        self.name_entry.pack()

    def enable_entry(self):
        self.name_entry.configure(state='normal')

    def disable_entry(self):
        self.name_entry.configure(state='disabled')


if __name__ == '__main__':
    
    Gui().mainloop()
Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
  • I see that you gave self as an argument for tk.Entry(). Would I have to do this for all of my other entries aswell? Also, thank you for actually explaining what to do. Most people on this platform would tell me to learn object oriented programming properly and downvote my question. – Lucy Oct 31 '20 at 15:15
  • Yes, and you are very welcomed. Widgets are represented in a tree where child widgets hold a reference to their parent. For a simple GUI with one window it will still work if you omit the parent; in that case, `tkinter` assigns `root` (of the tree) by default; however, I think it is better to build good habits, and explicitly designate the parent for all widgets. – Reblochon Masque Oct 31 '20 at 15:24
  • 1
    Ok, I understand. I also want to clear up my knowledge on OOP and I think I'm a little rusty. I'm going to watch a 1 hour tutorial on it. Thanks anyway. – Lucy Oct 31 '20 at 15:31
  • @Lucy This answer surely sums up the problem!, but take a look at my answer if your wondering on what other problems are faced here. – Delrius Euphoria Oct 31 '20 at 16:10