#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2013
    Location
    California, USA
    Posts
    66
    Rep Power
    2

    Add Functionality to Inherited Class


    This code is an attempt to create a home-made combo box class in a module.
    I'm at a road-block and can't figure out how to capture the chosen
    value from the calling module, for further processing.

    I use a listbox with a height of 1 to store the selected item, and
    underneath that is a 2nd listbox with scrollbar to choose one of multiple items.
    The chosen item is displayed in the #1 listbox. A command button
    expands or collapses the list of choices.
    Binding the #2 listbox causes the item clicked to be displayed in
    the #1 listbox.

    For starters, I would like to get the item choice to display in the
    label from the calling module.
    Code:
    #cust_combo.py
    
    try:
        from Tkinter import *     ## Python 2.x
    except ImportError:
        from tkinter import *     ## Python 3.x
        
    class Mycombo():
        def __init__(self, root, xPos=0, yPos=0,
                     fontFamily='Courier', fontSize=12,
                     headingText='',
                     listWidth=10,
                     listHeight=12,
                     add_scrollbar='none', cboList=''):
    
            self.listHeight = listHeight
            self.add_scrollbar = add_scrollbar.lower()
            
            __myframe = Frame(root, borderwidth=3, relief=GROOVE)
            __myframe.place(x=xPos, y=yPos)
    
            Label(__myframe, text=headingText,
                  font=(fontFamily, fontSize)).pack(anchor=NW)      
    
            __myshowbtn = Button(__myframe, text='v',
                                 width=2, height=1,
                                 command=self.__show_list)
            __myshowbtn.pack(side=RIGHT, anchor=NW)
    
            self.mycbo = Listbox(__myframe, width=listWidth,
                            font=(fontFamily, fontSize),
                            height=1
                            )                
            self.mycbo.pack(anchor=W)
    
            if self.add_scrollbar=='yes':
                self.mycbo.config(width=listWidth+2)
                self.scrollbar = Scrollbar(__myframe, orient=VERTICAL,
                                         command=self.__OnVSB)
                
            self.mylistbox = Listbox(__myframe, width=listWidth,
                            font=(fontFamily, fontSize),
                            height=1)
            
            self.pack_widgets(False)
            
            for r in range(0, len(cboList)):
                self.mylistbox.insert(END, cboList[r])
            
            self.mylistbox.bind('<ButtonRelease-1>', self.__collapse_list)
            
        def __show_list(self):
            try:
                x=len(self.mylistbox.pack_info())
                __isPacked = True
            except:
                __isPacked = False
    
            if __isPacked:
                self.pack_widgets(False)
            else:
                self.pack_widgets(True)
                
        def pack_widgets(self, __pack=True):
            if __pack:
                if self.add_scrollbar=='yes':
                    self.scrollbar.pack(side=RIGHT, anchor=N, fill=Y)
                    self.mylistbox.config(yscrollcommand=self.scrollbar.set)
                    
                self.mylistbox.pack(anchor=W)
                self.mylistbox.config(height=self.listHeight)    
            else:
                self.mylistbox.pack_forget()
                if self.add_scrollbar=='yes':
                    self.scrollbar.pack_forget()    
    
        def __collapse_list(self, event):
            __sel_item = self.mylistbox.curselection()
            self.mylistbox.selection_clear(0, END)
            self.mycbo.delete(0, END)
            self.mycbo.insert(0, self.mylistbox.get(int(__sel_item[0])))
            self.pack_widgets(False)
        
        def __OnVSB(self, *args):
            self.mylistbox.yview(*args)
    Code:
    try:
        from Tkinter import *     ## Python 2.x
    except ImportError:
        from tkinter import *     ## Python 3.x
    
    import cust_combo
    
    root = Tk()
    
    class MyApp():
    
        def __init__(self, root):
    
            cboList = ['eggs', 'bacon', 'spam', 'ham', 'hashbrowns', 'milk', 'juice', \
                      'pancakes', 'toast', 'dry cereal', 'oatmeal', 'orange']
    
            var = StringVar()
            choiceLabel = Label(root, textvariable=var,
                                bg='gray80',
                                padx=10, pady=4,
                                font=('Helvetica', 24, 'bold'))
            choiceLabel.pack(anchor=N)
            
            self.combo = cust_combo.Mycombo(root, xPos=200, yPos=200,
                                        fontFamily='Courier', fontSize=12,
                                        headingText='Click to Select',
                                        listWidth=12,
                                        listHeight=6,
                                        add_scrollbar='yes',
                                        cboList=cboList
                                        )
            
            closeBtn = Button(root, text='Close', font=('Helvetica', 16),
                              padx=4, pady=4, command=lambda: root.destroy())
            
            closeBtn.place(x=25, y=325)  
            
    app = MyApp(root)
    root.geometry('550x400+20+20')
    root.mainloop()
  2. #2
  3. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,709
    Rep Power
    480
    Where you have
    Code:
            closeBtn = Button(root, text='Close', font=('Helvetica', 16),
                              padx=4, pady=4, command=lambda: root.destroy())
            
            closeBtn.place(x=25, y=325)
    closeBtn is not used elsewhere, you needn't store it.

    root.destroy is already a function with correct argument signature, don't wrap it with lambda.

    Code:
            Button(root, text='Close', font=('Helvetica', 16),
                   padx=4, pady=4, command=root.destroy).place(x=25, y=325)
    Otherwise, I don't know what a combo box is supposed to be, nor can I tell how you want the program to behave. Nor am I particularly interested. I'm only looking because the test here at work failed, and the immediate problem is with the "front end" and I have "back end" skills. I'm stalling a short while rather than task-switching.
    [code]Code tags[/code] are essential for python code and Makefiles!
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Feb 2013
    Location
    California, USA
    Posts
    66
    Rep Power
    2

    reduced coding for cust_combo.py button widget


    B4Ö thanks for the instruction on the correct use of root.destroy, and in not coding unnecessary steps when adding a widget.

    For one of my personal projects, I needed a combo box to display a picklist of computer drive letters. From what I understand,
    Tkinter does not have a combo box widget, so I was faced with the choices of
    installing Pmw which has a combo box, or creating one myself.

    The intent of my question in the 1st post was to learn if a value
    selected in an inherited class could be available to the calling
    module to act upon immediately when an item was selected from the combo list (a list box made to drop down when a button is clicked).
    I realize that in some applications, this would be desirable, such
    as doing a filter as soon as an item is selected, and at other
    times a button click would be appropriate after making a selection.

    Besides receiving valuable advice from you, Iíve answered my own question.
    By putting the StringVar() variable inside the class, I can
    update the label in the calling module with the set() function
    as soon as a selection is made.

    This question has been answered, but any comments from the forum are welcome.
    The revised code below is my version of a combo box class
    created with Tkinter widgets, as well as the calling module that
    makes a new instance of the class.

    Code:
    #cust_combo.py
    
    try:
        from Tkinter import *     ## Python 2.x
    except ImportError:
        from tkinter import *     ## Python 3.x
        
    class Mycombo():
        def __init__(self, root, xPos=0, yPos=0,
                     fontFamily='Courier', fontSize=12,
                     headingText='',
                     listWidth=10,
                     listHeight=12,
                     add_scrollbar='none', cboList=''):
    
            self.listHeight = listHeight
            self.add_scrollbar = add_scrollbar.lower()
            self.cboValue = StringVar()
            
            __myframe = Frame(root, borderwidth=3, relief=GROOVE)
            __myframe.place(x=xPos, y=yPos)
    
            Label(__myframe, text=headingText,
                  font=(fontFamily, fontSize)).pack(anchor=NW)      
    
            Button(__myframe, text='v',
                            width=2, height=1,
                            command=self.__show_list).pack(side=RIGHT, anchor=NW)
            
            self.mycbo = Listbox(__myframe, width=listWidth,
                            font=(fontFamily, fontSize),
                            height=1
                            )                
            self.mycbo.pack(anchor=W)
    
            if self.add_scrollbar=='yes':
                self.mycbo.config(width=listWidth+2)
                self.scrollbar = Scrollbar(__myframe, orient=VERTICAL,
                                         command=self.__OnVSB)
                
            self.mylistbox = Listbox(__myframe, width=listWidth,
                            font=(fontFamily, fontSize),
                            height=1)
            
            self.pack_widgets(False)
            
            for r in range(0, len(cboList)):
                self.mylistbox.insert(END, cboList[r])
            
            self.mylistbox.bind('<ButtonRelease-1>', self.__collapse_list)
            
        def __show_list(self):
            try:
                x=len(self.mylistbox.pack_info())
                self.pack_widgets(False)
            except:
                self.pack_widgets(True)
    
        def pack_widgets(self, __pack=True):
            if __pack:
                if self.add_scrollbar=='yes':
                    self.scrollbar.pack(side=RIGHT, anchor=N, fill=Y)
                    self.mylistbox.config(yscrollcommand=self.scrollbar.set)
                    
                self.mylistbox.pack(anchor=W)
                self.mylistbox.config(height=self.listHeight)    
            else:
                self.mylistbox.pack_forget()
                if self.add_scrollbar=='yes':
                    self.scrollbar.pack_forget()    
    
        def __collapse_list(self, event):
            __sel_item = self.mylistbox.curselection()
            self.mylistbox.selection_clear(0, END)
            self.mycbo.delete(0, END)
            self.mycbo.insert(0, self.mylistbox.get(int(__sel_item[0])))
            self.cboValue.set(self.mylistbox.get(int(__sel_item[0])))
            self.pack_widgets(False)
        
        def __OnVSB(self, *args):
            self.mylistbox.yview(*args)
    Code:
    try:
        from Tkinter import *     ## Python 2.x
    except ImportError:
        from tkinter import *     ## Python 3.x
    
    import cust_combo
    
    root = Tk()
    
    class MyApp():
    
        def __init__(self, root):
    
            cboList = ['eggs', 'bacon', 'spam', 'ham', 'hashbrowns', 'milk', 'juice', \
                      'pancakes', 'toast', 'dry cereal', 'oatmeal', 'orange']
    
            self.combo = cust_combo.Mycombo(root, xPos=180, yPos=200,
                                        fontFamily='Courier', fontSize=12,
                                        headingText='Click to Select',
                                        listWidth=12,
                                        listHeight=6,
                                        add_scrollbar='yes',
                                        cboList=cboList
                                        )
    
            Label(root, textvariable=self.combo.cboValue,
                        bg='gray80',
                        padx=10, pady=4,
                        font=('Helvetica', 24, 'bold')).pack(anchor=N)
            
            Button(root, text='Close', font=('Helvetica', 16),
                   padx=4, pady=4,
                   command=root.destroy).place(x=25, y=325)
           
    app = MyApp(root)
    root.geometry('550x400+20+20')
    root.mainloop()
    Last edited by pyJer; November 20th, 2013 at 04:45 PM.
  6. #4
  7. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,709
    Rep Power
    480
    thank you for teaching me about combo boxes.

    Please note: the tix and ttk modules, both now part of the python distribution in the tkinter directory, have combo box widgets.

    class ComboBox(TixWidget): # Tix


    class Combobox(Entry): # Ttk
    [code]Code tags[/code] are essential for python code and Makefiles!
  8. #5
  9. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Feb 2005
    Posts
    588
    Rep Power
    64
    An alternative, actually Tkinter has a combobox it's just called something else ...
    Code:
    ''' tk_OptionMenu2.py
    using Tkinter's OptionMenu() as a combobox
    allows one item to be selected
    can use trace() and globalgetvar(name) to show selected choice
    '''
    
    try:
        # Python2
        import Tkinter as tk
    except ImportError:
        # Python3
        import tkinter as tk
    
    def show_choice(name, index, mode):
        sf = "value is %s" % root.globalgetvar(name)
        root.title(sf)
    
    
    root = tk.Tk()
    
    choices = ['red', 'green', 'blue', 'yellow','white']
    color = tk.StringVar(root)
    color.trace('w', show_choice)
    
    # optionally preselect a choice
    color.set(choices[2])
    
    color_option = tk.OptionMenu(root, color, *choices)
    color_option.pack(padx=70, pady=10)
    
    root.mainloop()
    Last edited by Dietrich; November 21st, 2013 at 12:23 PM.
    Real Programmers always confuse Christmas and Halloween because Oct31 == Dec25
  10. #6
  11. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Feb 2005
    Posts
    588
    Rep Power
    64
    As mentioned by b....
    Code:
    ''' tix_ComboBox2.py
    explore the tix.ComboBox()
    the Tix (Tk Interface Extension) module comes with the
    Python27 and Python31+ installation
    '''
    
    try:
        import Tix as tix  # Python27
    except ImportError:
        import tkinter.tix as tix  # Python31+
    
    def selected(event=None):
        color = combo.entry.get()
        root.title("color value is {}".format(color))
        root['bg'] = color  # simple test
    
    
    root = tix.Tk()
    # use width x height + x_offset + y_offset (no spaces!)
    root.geometry("{}x{}+{}+{}".format(330, 80, 200, 150))
    root.title("tix.ComboBox()")
    
    # apply a label and make the combo entry editable
    combo = tix.ComboBox(root, label='Color:', editable=1)
    combo.pack(side='left', padx=10, pady=10)
    
    # load the combobox listbox
    color_list = ['red', 'green', 'blue', 'yellow', 'white', 'magenta']
    for item in color_list:
        combo.insert('end', item)
    
    # set the initial color
    # make combobox editable to do this
    combo.entry.insert(0, 'red')
    # start with the color in the entry
    selected()
    
    # left mouse click on a list item to display selection
    combo.slistbox.listbox.bind('<ButtonRelease-1>', selected)
    
    root.mainloop()
    Last edited by Dietrich; November 21st, 2013 at 12:27 PM.
    Real Programmers always confuse Christmas and Halloween because Oct31 == Dec25

IMN logo majestic logo threadwatch logo seochat tools logo