-1

I want to display a Options menu which has various options to select. editionMap, topicMap, langMap all are dictionaries. I am trying to make a single options menu and then make instances of it.

import tkinter as tk
from utils import editionMap, topicMap, langMap

class OptionMenu:
    """Constructor Function"""
    def __init__(self, master, status, *options):
        self.frame = Frame(master)
        frame.pack()

        self.dropdown = tk.StringVar()
        self.dropdown.set("status")


def main():
    root = tk.Tk()
    menu1 = OptionMenu(root, "Language", *langMap.keys())
    menu1.pack()
    root.mainloop()

if __name__ == '__main__':
    main()

I am want to make optionsmenu using classes (see screenshot):

enter image description here

On creating class OptionMenu I am getting errors and only GUI window opens which is blank

 Traceback (most recent call last):
  File "F:\KWOC gnewsclient\gnewsclient\gnewsclient\test.py", line 22, in <module>
    main()
  File "F:\KWOC gnewsclient\gnewsclient\gnewsclient\test.py", line 18, in main
    menu1.pack()
AttributeError: 'OptionMenu' object has no attribute 'pack'
Ice fire
  • 143
  • 3
  • 10
  • 1
    you need to use `tk.Frame` because that is how you imported tkinter, if you had done `from tkinter import *` (not that i recommend this) then what you have above would work for the frame (but not for your stringvar or root window) – James Kent Dec 12 '17 at 14:21
  • You need to use `tk.Frame` instead. – Nae Dec 12 '17 at 14:21
  • 1
    In addition, it should be `self.frame.pack()` not `frame.pack()` in `__init__` – j_4321 Dec 12 '17 at 14:22
  • @j_4321 I have done changes but it gives `StringVar does not have attribute (attribute error)` – Ice fire Dec 12 '17 at 14:26
  • 1
    You are trying to pack the `StringVar` with `self.dropdown.pack()`, but it is not a widget. – j_4321 Dec 12 '17 at 14:30
  • @j_4321 Check code I have edited but still error – Ice fire Dec 12 '17 at 14:35
  • @JamesKent I have made necessary changes in code but still giving error – Ice fire Dec 12 '17 at 14:41
  • you biggest mistake - you create own `OptionMenu` but you doesn't use original `tk.OptionMenu` inside. – furas Dec 12 '17 at 14:49
  • @furas If possible can you edit code and tell I am not able to understand – Ice fire Dec 12 '17 at 14:51
  • @bryan Oakley I have edited the question – Ice fire Dec 12 '17 at 14:51
  • @Icefire we can continue the discussion in the chat: https://chat.stackoverflow.com/rooms/161035/getting-error-when-using-class-in-tkinter-oop – j_4321 Dec 12 '17 at 14:56
  • 1
    Your edit just changes it to be a duplicate of a different question. Please do a little research before asking such basic questions. Simply searching this site for "object has no attribute pack" yields results that might be helpful. – Bryan Oakley Dec 12 '17 at 15:00

1 Answers1

1

You create own OptionMenu with Frame inside but without original tk.OptionMenu

import tkinter as tk

langMap = {1:"English", 2:"German", 3:"Russian"}

class MyOptionMenu1():  # <-- without inheritions it is not widget, 
                        # You can't use `menu1.pack()`.
                        # You could use only `menu1.frame.pack()`.
                        # Or you have to create own `def pack(self, **options)
                        #    and execute `self.frame.pack()` inside

    def __init__(self, master, status, *options):

        self.frame = tk.Frame(master) # <-- tk.
        self.frame.pack() # <-- self.

        self.result = tk.StringVar()
        #self.result.set(status)

        self.label = tk.Label(self.frame, text=status)
        self.label.pack()

        self.dropdown = tk.OptionMenu(self.frame, self.result, *options)
        self.dropdown.pack()


class MyOptionMenu2(tk.Frame): # <-- inherits from Frame

    def __init__(self, master, status, *options):

        super().__init__(master) # Frame constructor
        #self.pack() # <-- without - use `menu1.pack()` to show this frame 

        self.result = tk.StringVar()
        #self.result.set(status)

        self.label = tk.Label(self, text=status) # <-- self as parent/master
        self.label.pack()

        self.dropdown = tk.OptionMenu(self, self.result, *options) # <-- self as parent/master
        self.dropdown.pack()


def main():
    root = tk.Tk()

    # --- version 1 ---

    menu1 = MyOptionMenu1(root, "Language", *langMap.keys()) # <-- tk.
    #menu1.pack() # <--- without, because MyOptionMenu1 is not widget

    menu1 = MyOptionMenu1(root, "Language", *langMap.values()) # <-- tk.
    #menu1.pack() # <--- without, because MyOptionMenu1 is not widget

    # --- version 2 ---

    menu1 = MyOptionMenu2(root, "Language", *langMap.keys()) # <-- tk.
    menu1.pack() # <--- with, because MyOptionMenu2 is widget 

    menu1 = MyOptionMenu2(root, "Language", *langMap.values()) # <-- tk.
    menu1.pack() # <--- without, because MyOptionMenu is not widget

    root.mainloop()

if __name__ == '__main__':
    main()

EDIT: code with layout changes but without some comments

import tkinter as tk

class MyOptionMenu1(): # <-- not inherits from Frame 

    def __init__(self, master, status, *options):

        self.frame = tk.Frame(master) # internal class
        self.frame.pack(anchor='w') # show in window

        self.result = tk.StringVar(value=options[0])

        self.label = tk.Label(self.frame, text=status)
        self.label.pack(side='left')

        self.dropdown = tk.OptionMenu(self.frame, self.result, *options)
        self.dropdown.pack()


class MyOptionMenu2(tk.Frame): # <-- inherits from Frame

    def __init__(self, master, status, *options):

        super().__init__(master) # Frame constructor
        #self.pack(anchor='w') # show in window (but you can do it outside

        self.result = tk.StringVar(value=options[0])

        self.label = tk.Label(self, text=status) # <-- self as parent/master
        self.label.pack(side='left')

        self.dropdown = tk.OptionMenu(self, self.result, *options) # <-- self as parent/master
        self.dropdown.pack()


if __name__ == '__main__':

    langMap = {1:"English", 2:"German", 3:"Russian"}

    root = tk.Tk()

    # --- version 1 ---

    menu = MyOptionMenu1(root, "Language", *langMap.keys())
    #menu.pack() # <--- without pack(),
                 # because MyOptionMenu1 is not widget
                 # and it doesn't have this method

    menu = MyOptionMenu1(root, "Language", *langMap.values())
    #menu.pack() # <--- without pack(),
                 # because MyOptionMenu1 is not widget
                 # and it doesn't have this method

    # --- version 2 ---

    menu = MyOptionMenu2(root, "Language", *langMap.keys())
    menu.pack(anchor='w') # <--- with pack()
                          # because MyOptionMenu2 is widget 

    menu = MyOptionMenu2(root, "Language", *langMap.values())
    menu.pack(anchor='w') # <--- with pack()
                          # because MyOptionMenu2 is widget

    # --- start ---

    root.mainloop()

enter image description here

furas
  • 134,197
  • 12
  • 106
  • 148