Search code examples
pythontkintercomboboxtk-toolkitttk

Combobox not displaying (Tkinter)


Im trying to use a combobox in my program.

To simplify my program, my main window uses an image as a background, and my buttons and entry boxes I wont include since they arent relavent. The code for my main window is:

from tkinter.ttk import Combobox
from tkinter.ttk import *
import tkinter as tk #importing tkinter library
from tkinter import * #importing everything from tkinter library

def main_window():
        # create a new window
    invoice = Toplevel()
    # load the image file
    billimage1 = PhotoImage(file="C:/Users/hasee/OneDrive/Documents/CODE/billimage.PNG")
    # create a label widget and set it as the background of the window
    label2 = Label(invoice, image = billimage1)
    label2.pack()

Im creating a function to include the combobox and calling it under the main_window function so it can be displayed over my image background. The code for it:

def dropdown():
 # create the Combobox widget
 options = ["option1", "option2", "option3"]
 combobox = ttk.Combobox(invoice, values=options)

 # create a frame to hold the Combobox
 frame = tk.Frame(invoice, width=200, height=50)
 frame.pack()

 # add the Combobox to the frame
 combobox.place(x=50, y=50)
dropdown()

If I dont call it, the program is runnable but is not displayed but when I do call it, it gives me an error saying: AttributeError: module 'tkinter' has no attribute 'Combobox'.

I have the latest version of Python installed so that cant be the problem.

I tried packing it, then using place() but none of it worked. I kept on getting the error and so I uninstalled and then installed Python again yet im still receiving the error. Please Help!


Solution

  • There are many problems in your code.
    I added line numbers and modified the indentation :

     1 from tkinter.ttk import Combobox
     2 from tkinter.ttk import *
     3 import tkinter as tk #importing tkinter library
     4 from tkinter import * #importing everything from tkinter library
     5
     6 def main_window():
     7     # create a new window
     8     invoice = Toplevel()
     9     # load the image file
    10     billimage1 = PhotoImage(file="C:/Users/hasee/OneDrive/Documents/CODE/billimage.PNG")
    11     # create a label widget and set it as the background of the window
    12     label2 = Label(invoice, image = billimage1)
    13     label2.pack()
    14
    15 def dropdown():
    16     # create the Combobox widget
    17     options = ["option1", "option2", "option3"]
    18     combobox = ttk.Combobox(invoice, values=options)
    19
    20     # create a frame to hold the Combobox
    21    frame = tk.Frame(invoice, width=200, height=50)
    22    frame.pack()
    23
    24    # add the Combobox to the frame
    25    combobox.place(x=50, y=50)
    

    The code you posted is obviously incomplete : it is unclear where you placed the dropdown() call, it should be inside the main_window function.
    Also, main_window should call invoice.mainloop() or otherwise the window wouldn't be displayed at all.

    'star' imports such as line 2 & 4 are considered bad practice since more modules may contain the same names (like here : both tkinter and tkinter.ttk have a Label class, among others).
    Line 1 imports Combobox from tkinter.ttk, then line 2 imports it again (along with everything else in that module).
    Line 3 imports tkinter as tk, then line 4 imports everything from that module.

    It is common practice to use these imports :

    import tkinter as tk  
    import tkinter.ttk as ttk
    

    this requires to use explicitly the module alias on the left side of any widget : ttk.Combo, tk.Toplevel, tk.Frame, tk.Label, and so on.
    This avoids name collision.

    Line 8 declares a Toplevel without specifying its parent. Doing so, tkinter will create a Tk instance automatically that appears on screen as an empty window. If your application has a single window, you should create invoice as Tk to avoid this.
    Otherwise, create the main window as Tk and declare the child windows as Toplevel with the main window as parent, as :

    root = tk.Tk()  
    child_window = tk.Toplevel(root)  
    

    Another way to get rid of the empty Tk is to hide it :

    root = tk.Tk()
    invoice = tk.Toplevel(root)
    root.withdraw()
    

    (since the function is called main_window, I would use tk.Tk()).

    Is there any reason for using a function instead of adding the combobox in main_window ?
    If not so, just place the code in the main_window. Better yet, rename the function create_main_window so that its purpose is clear.
    If instead you need a separate function, you must declare invoice as global and state so in the dropdown function (which should be renamed create_dropdown, see above) :

    def create_dropdown():
        global invoice
        ...
        combobox = ttk.Combobox(invoice, values=options)
        ...
    

    You can avoid this by adding a parent argument :

    def create_dropdown(parent):
        ...
        combobox = ttk.Combobox(parent, values=options)
        ...
    

    and call it in create_main_window :

    ...
    create_dropdown(invoice)
    ...
    

    Line 20 reads '# create a frame to hold the Combobox' but actually the combobox is created on line 18 as a child of invoice.
    If you want to add the combobox inside the frame, you must first create the frame and then create the combobox with the frame as parent.

    Here is a sample that creates a window with the required background and adds a combobox :

    def create_main_window():    
        # create a new window
        invoice = tk.Tk()
        
        # assumes that the image is in the same directory
        # (I am on Linux, check if this works on Windows)
        image_file = './billing.png'
        
        # create the image
        billimage1 = tk.PhotoImage(file=image_file)
        
        # create a label widget and set it as the background of the window
        label2 = tk.Label(invoice, image=billimage1)
    
        label2.pack()
    
        options = ["option1", "option2", "option3"]
        combobox = ttk.Combobox(invoice, values=options)
    
        combobox.place(x=50, y=50)
    
        invoice.mainloop()
    
    
    if __name__ == '__main__':
        create_main_window()