'Python3, difficulty with classes and tkinter

First of all to kick it off,

  • I'm not great at programming,
  • I have difficulty with understanding most basics,
  • I always try doing my uterly best to solve things like this myself.

I'm trying to create a simple gui that makes json files. Everything works fine. Fine in the sense that I'm able to create the files. Now I wanted to get my code cleaned up and to the next level. I have added tabs to the tkinter screen and that is where the troubles starts. Because when I'm, on a differend tab, the function doesn't get the current selected items, so I added buttons to save that list and then move to different tab.

I have a function(Save_List_t), which looks at the selected items from the listbox(a_lsb1) and saves them to a list(choice_list_t). This function runs when I press button(a_button).

After doing that I got a problem, I don't want to use "global" but I need the list in a other function(Mitre_Gen_Techs) to generate the files. This function runs when I press a button on the third tab.(c.button1)

To tackel this problem, I saw a post where someone uses a class to fix it. However even after reading to the documentation about classes I still don't truely get it.

Now I'm stuck and get the error. Which I don't find that strange, it makes sense to me why it gives the error but what am I doing wrong or how do I solve this issue.

The error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\thans\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
    return self.func(*args)
TypeError: Save_List_t() missing 1 required positional argument: 'self'

The code I wrote:

from tkinter import *
from attackcti import attack_client
from mitretemplategen import *
from tkinter import ttk


# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mitre ATT&Ck
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ac = attack_client()
groups = ac.get_groups()
groups = ac.remove_revoked(groups)
techs = ac.get_enterprise_techniques()
techs = ac.remove_revoked(techs)


# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Tkinter screen setup
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
root = Tk()

root.title("Mitre Att&ck")
root.minsize(900, 800)
root.wm_iconbitmap('')


# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Functions / classes
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

class Screen(object):
    def __init__(self):
        self.choice_list_t = []
        self.choice_list_g = []


    def Save_List_t(self):
        for item in a_lsb2.curselection():
            self.choice_list_t.append(a_lsb2.get(item))
        print(self.choice_list_t)


    def Save_List_g(self):
        choice_list_g = []
        for item in b_lsb1.curselection():
            self.choice_list_g.append(b_lsb1.get(item))
        print(self.choice_list_g)


    def Mitre_Gen_Techs(self):
        # Gen the json file
        # mitre_gen_techs(self.choice_list_t, techs)

        #testing class
        print(self.choice_list_t)


    def Mitre_Gen_Groups(self):
        # Gen the json file
        # mitre_gen_groups(self.choice_list_g, groups)

        #testing class
        print(self.choice_list_g)



def main():
    # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    # First Tkinter tab
    # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
    rows = 0
    while rows < 50:
        root.rowconfigure(rows, weight=1)
        root.columnconfigure(rows, weight=1)
        rows += 1

    # Notebook creating tabs
    nb = ttk.Notebook(root)
    nb.grid(row=1, column=0, columnspan=50, rowspan=50, sticky='NESW')

    # Create the differend tabs on the notebook
    tab_one = Frame(nb)
    nb.add(tab_one, text='APG')

    tab_two = Frame(nb)
    nb.add(tab_two, text='Actors')

    tab_gen = Frame(nb)
    nb.add(tab_gen, text='test')


    # =-=- First Tab -=-=
    # List box 1
    a_lsb1 = Listbox(tab_one, height=30, width=30, selectmode=MULTIPLE)
    # List with techs
    a_lsb2 = Listbox(tab_one, height=30, width=30, selectmode=MULTIPLE)
    for t in techs:
        a_lsb2.insert(END, t['name'])


    # Save list, to later use in Screen.Mitre_Gen_Techs
    a_button = Button(tab_one, text="Save selected", command=Screen.Save_List_t)


    # =-=- Second Tab -=-=
    # List with TA's
    b_lsb1 = Listbox(tab_two, height=30, width=30, selectmode=MULTIPLE)
    for g in groups:
        b_lsb1.insert(END, g['name'])

    # Save list, to later use in Screen.Mitre_Gen_Groups
    b_button = Button(tab_two, text="Save selected", command=Screen.Save_List_g)


    # =-=- Third tab -=-=
    c_button = Button(tab_gen, text="Print group json", command=Screen.Mitre_Gen_Groups)
    c_button1 = Button(tab_gen, text="Print techs json", command=Screen.Mitre_Gen_Techs)


    # Placing the items on the grid
    a_lsb1.grid(row=1, column=1)
    a_lsb2.grid(row=1, column=2)

    b_lsb1.grid(row=1, column=1)

    a_button.grid(row=2, column=1)
    b_button.grid(row=2, column=1)

    c_button.grid(row=2, column=1)
    c_button1.grid(row=2, column=2)


    root.mainloop()

# If main file then run: main()
if __name__ == "__main__":
    main()

The application: Image



Solution 1:[1]

I found someone who explained what was wrong. Credits to Scriptman ( ^ , ^ ) /

simply adding: sc = Screen()

And changing: Button(tab_apg, text="Save selected", command=sc.Save_List_t)

Resolved the issue.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 hashtagplague