Search code examples
pythondrop-down-menutkintertext-widget

python tkinter: use a drop-down menu to enable a text field


as a side project to my usual work, I was asked to create a form to collect information. Now the script is in shape and basically does all that I needed, but I would like to add an extra feature. Basically, I have some fields that are made of 3 widgets: a Label with some question, a drop-down menu with a "Yes"/"No" list to select and an optional text widget where the User could provide extra information (usually if the selection from the drop-down was "Yes") Currently the text widget is always active (i.e. the User can write everything that I wants) and it is just during a post-processing phase (made by the script) that I collect its content depending on the value of the drop-down selection.

This is basically fine, but I would like to have it more visually appealing by having the text widget enabled or not depending by the value of the drop-down. Basically, my idea is to have the text widget disabled by default, and if the User select "Yes" from the drop list, then the widget become editable.

I tried to do it like this:

#! /bin/env python


from Tkinter import *
#

my_change = "No"


stateOpts = ['normal','disabled']


win_width = 610
win_height =866

# My frame for form
class simpleform_ap(Tk):

    #my_sel = ""
    global my_change

    # constructor
    def __init__(self,parent):
        Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()
    #

    def initialize(self):
        #
        # Default Window Size
        self.geometry(str(win_width) + "x" + str(win_height))
        #
        self.grid_columnconfigure(0,weight=4)
        self.grid_rowconfigure(0,weight=1)
        #
        # Create a Canvas
        self.canvas=Canvas(self.parent)
        self.canvas.grid(row=0,column=0,sticky='nsew')
        #
        # Add a Frame inside my canvas
        self.frame1 = Frame(self.canvas)
        #
        # Create canvas window
        self.canvas.create_window(0,0,window=self.frame1,anchor='nw')
        #
        curr_row = 1
        text_height = 8
        text_width = 5*text_height
        # Label
        self.labelVariableChanges = StringVar()  # Label variable
        labelChanges=Label(self.frame1,textvariable=self.labelVariableChanges,
                 anchor="nw",
                 fg="Black")
        labelChanges.grid(column=0,row=curr_row,columnspan=1,sticky='EW')
        self.labelVariableChanges.set("Do your selection: ")
        # Selection
        optionList = ["Yes","No"]
        self.dropVarChanges=StringVar()
        self.dropVarChanges.set("Select")
        self.dropMenuChanges = OptionMenu(self.frame1 ,self.dropVarChanges,
                                            *optionList, command=self.get_Change_selection)
        self.dropMenuChanges.grid(column=2,row=curr_row)
        curr_row = curr_row+1
        # Text
        self.textStateChanges = stateOpts[1]
        self.TextVarChanges=StringVar()
        #
        self.textChanges=Text(self.frame1,state=self.textStateChanges,
                            height = text_height, width = text_width,
                            fg="black",bg="white") # ,textvariable=self.myTextVar)
        #
        self.textChanges.grid(column=1, row=curr_row+3, columnspan=2, sticky='EW')
        self.textChanges.insert('1.0',"If Yes, add changes here!")
        #
        #
        # Update Geometry
        self.update()
        self.geometry(self.geometry() )
        self.frame1.update_idletasks()
        self.canvas.config(scrollregion=(0,0,self.frame1.winfo_width(),self.frame1.winfo_height()))
        #
        # end initialize()


    def get_Change_selection(self,value):
        global my_change
        #
        my_change = value
        if value == 'Yes':
        #
            self.textStateChanges = stateOpts[0]
            #
        self.dropVarChanges.set(value)
        return


def release_block(argv):
    # Create Form
    form = simpleform_ap(None)
    form.title('Release Information')
    #
    form.mainloop()

    print "Done"
    #



if __name__ == "__main__":
    release_block(sys.argv)

but I failed (basically I am a n00b with TKinter).

I guess the problem is in the mainloop and in the function to retrieve the selection, but I cannot figure out how to solve this.

Does anybody have an idea on how to fix this?

Thanks in advance to everybody that is willing to give me some hints.


Solution

  • You can enable/disable the text widget by calling self.textChanges.config() and passing it the state. This amounts to modifying your get_Change_selection to read:

    def get_Change_selection(self,value):
        global my_change
        my_change = value
        if value == 'Yes':
            self.textChanges.config(state=stateOpts[0])
        else:
            self.textChanges.config(state=stateOpts[1])
        self.dropVarChanges.set(value)
    
        return
    

    If you'd like to disable the field by default, add a call to config in the constructor to disable it. After making these changes, your code would look like:

    from Tkinter import *
    #
    
    my_change = "No"
    
    
    stateOpts = ['normal', 'disabled']
    
    
    win_width = 610
    win_height =866
    
    # My frame for form
    class simpleform_ap(Tk):
    
        #my_sel = ""
        global my_change
    
        # constructor
        def __init__(self,parent):
            Tk.__init__(self,parent)
            self.parent = parent
            self.initialize()
        #
    
        def initialize(self):
            #
            # Default Window Size
            self.geometry(str(win_width) + "x" + str(win_height))
            #
            self.grid_columnconfigure(0,weight=4)
            self.grid_rowconfigure(0,weight=1)
            #
            # Create a Canvas
            self.canvas=Canvas(self.parent)
            self.canvas.grid(row=0,column=0,sticky='nsew')
            #
            # Add a Frame inside my canvas
            self.frame1 = Frame(self.canvas)
            #
            # Create canvas window
            self.canvas.create_window(0,0,window=self.frame1,anchor='nw')
            #
            curr_row = 1
            text_height = 8
            text_width = 5*text_height
            # Label
            self.labelVariableChanges = StringVar()  # Label variable
            labelChanges=Label(self.frame1,textvariable=self.labelVariableChanges,
                               anchor="nw",
                               fg="Black")
            labelChanges.grid(column=0,row=curr_row,columnspan=1,sticky='EW')
            self.labelVariableChanges.set("Do your selection: ")
            # Selection
            optionList = ["Yes","No"]
            self.dropVarChanges=StringVar()
            self.dropVarChanges.set("Select")
            self.dropMenuChanges = OptionMenu(self.frame1 ,self.dropVarChanges,
                                              *optionList, command=self.get_Change_selection)
            self.dropMenuChanges.grid(column=2,row=curr_row)
            curr_row = curr_row+1
            # Text
            self.textStateChanges = stateOpts[1]
            self.TextVarChanges=StringVar()
            #
            self.textChanges=Text(self.frame1,state=self.textStateChanges,
                                  height = text_height, width = text_width,
                                  fg="black",bg="white") # ,textvariable=self.myTextVar)
            #
            self.textChanges.grid(column=1, row=curr_row+3, columnspan=2, sticky='EW')
            self.textChanges.insert('1.0',"If Yes, add changes here!")
            self.textChanges.config(state=stateOpts[1])
            #
            #
            # Update Geometry
            self.update()
            self.geometry(self.geometry() )
            self.frame1.update_idletasks()
            self.canvas.config(scrollregion=(0,0,self.frame1.winfo_width(),self.frame1.winfo_height()))
            #
            # end initialize()
    
    
        def get_Change_selection(self,value):
            global my_change
            my_change = value
            if value == 'Yes':
                self.textChanges.config(state=stateOpts[0])
            else:
                self.textChanges.config(state=stateOpts[1])
            self.dropVarChanges.set(value)
    
            return
    
    
    def release_block(argv):
        # Create Form
        form = simpleform_ap(None)
        form.title('Release Information')
        #
        form.mainloop()
    
        print("Done")
        #
    
    
    
    if __name__ == "__main__":
        release_block(sys.argv)