-2

Why I continue getting the error :

missing 1 required positional argument: 'category_id'

when the argument is already passed within query function in Backend class? I also don't understand the error of unfilled self or missing positional argument self:

missing 1 required positional argument: 'self'

I tried passing self to display_account_types() in Frontend class but it doesn't reflect. Do I need to pass self within the inner nested functions within a class?

import tkinter
from tkinter import *
from tkinter import ttk
import tkinter.messagebox
import sqlite3

root =Tk()
root.title('Simple  Application')
root.config(bg='SlateGrey')
root.geometry("")

# BackEnd
class Backend():
    def __init__(self):
        self.conn = sqlite3.connect('accounting.db')
        self.cur = self.conn.cursor()

        self.conn.execute("""CREATE TABLE IF NOT EXISTS account_type(
         id             INTEGER      PRIMARY KEY,
         category_type    INTEGER      NOT NULL,
         category_id      TEXT         NOT NULL
         )"""),

        self.conn.commit()
        self.conn.close()

    def insert_account_type(self, category_type, category_id):
        self.conn = sqlite3.connect('accounting.db')
        self.cur = self.conn.cursor()
        self.cur.execute("""INSERT INTO  account_type(category_id, category_type) VALUES(?,?);""",
                         (self,category_type, category_id,))
        self.conn.commit()
        self.conn.close()

    def view_account_type(self):
        self.conn = sqlite3.connect('accounting.db')
        self.cur = self.conn.cursor()
        self.cur.execute("SELECT * FROM account_type")
        self.rows = self.cur.fetchall()
        self.conn.close()
        return self.rows

# calling the class
tb = Backend()

# Front End
class Frontend():
    def __init__(self, master):
        # Frames

        self.top_frame = LabelFrame(master,bg ='SlateGrey', relief=SUNKEN)
        self.top_frame.pack()

        self.bottom_frame = LabelFrame(master, bg = 'SlateGrey', relief=SUNKEN)
        self.bottom_frame.pack()

        self.right_frame = LabelFrame(self.top_frame, bg = 'SlateGrey', relief = FLAT,
                                      text = 'Details Entry',fg = 'maroon')
        self.right_frame.pack(side = RIGHT, anchor = NE)

        self.side_frame = LabelFrame(self.top_frame,bg ='SlateGrey',relief=SUNKEN,text = 'Menu Buttons',fg = 'maroon')
        self.side_frame.pack(side = LEFT,anchor = NW)

        self.bot_frame = LabelFrame(self.bottom_frame, bg='Grey',relief = SUNKEN,text = 'Field View',fg = 'maroon')
        self.bot_frame.pack(side = BOTTOM,anchor = SW)

        # Side Buttons
        self.btn1 = Button(self.side_frame,
                           text='Main Account Types',
                           bg='SteelBlue4',
                           font=('cambria', 11),
                           anchor=W,
                           fg='white',
                           width=18,height=2,
                           command=lambda :[self.main_account()])
        self.btn1.grid(row=0, column=0, pady=0, sticky=W)

    def main_account(self):

        # variables
        self.category_type = StringVar()
        self.category_id = StringVar()

        # functions
        def add_main_accounts():
            if self.category_type.get() == "" or self.category_id.get() == "":
                tkinter.messagebox.showinfo('All fields are required')
            else:
                Backend.insert_account_type(
                    self.category_type.get(),
                    self.category_id.get(),)   # category type unfilled

                tkinter.messagebox.showinfo('Entry successful')

        def display_account_types(self):
            self.trv.delete(*self.trv.get_children())
            for self.rows in Backend.view_account_type(self):
                self.trv.insert("", END, values=self.rows)

        def get_account_type(e):
            self.selected_row = self.trv.focus()
            self.data = self.trv.item(self.selected_row)
            global row
            row = self.data["values"]

            """Grab items and send them to entry fields"""
            self.category_id.set(row[1])
            self.category_type.set(row[2])

        """=================TreeView==============="""
        # Scrollbars
        ttk.Style().configure("Treeview", background = "SlateGrey", foreground = "white", fieldbackground = "grey")

        scroll_x = Scrollbar(self.bot_frame, orient = HORIZONTAL)
        scroll_x.pack(side = BOTTOM, fill = X)

        scroll_y = Scrollbar(self.bot_frame, orient = VERTICAL)
        scroll_y.pack(side = RIGHT, fill = Y)

        # Treeview columns & setting scrollbars
        self.trv = ttk.Treeview(self.bot_frame, height=3, columns=
        ('id', 'category_id', 'category_type'), xscrollcommand = scroll_x.set, yscrollcommand = scroll_y.set)

        # Treeview style configuration
        ttk.Style().configure("Treeview", background = "SlateGrey", foreground = "white", fieldbackground = "grey")

        # Configure vertical and Horizontal scroll
        scroll_x.config(command = self.trv.xview)
        scroll_y.config(command = self.trv.yview)

        # Treeview Headings/columns
        self.trv.heading('id', text = "No.")
        self.trv.heading('category_id', text = 'Category ID')
        self.trv.heading('category_type', text = 'Category Type')

        self.trv['show'] = 'headings'

        # Treeview columns width
        self.trv.column('id', width = 23)
        self.trv.column('category_id', width = 70)
        self.trv.column('category_type', width = 100)

        self.trv.pack(fill = BOTH, expand = YES)

        # Binding Treeview with data
        self.trv.bind('<ButtonRelease-1>',get_account_type)

        # Account Types Labels
        self.lbl1 = Label(self.right_frame,text = 'Category ID',anchor = W,
                          width=10,font = ('cambria',11,),bg = 'SlateGrey')
        self.lbl1.grid(row = 0,column = 0,pady = 5)

        self.lbl2 = Label(self.right_frame, text = 'Category Type', anchor = W,
                          width = 10,font = ('cambria',11,),bg = 'SlateGrey')
        self.lbl2.grid(row = 1, column = 0,pady = 5,padx=5)

        self.blank_label = Label(self.right_frame, bg='SlateGrey')
        self.blank_label.grid(row=2, columnspan=2, pady=10)

        # Account Type Entries
        self.entry1 = Entry(self.right_frame,textvariable = self.category_id,
                            font = ('cambria',11,),bg = 'Grey',width=14)
        self.entry1.grid(row = 0,column=1,sticky = W,padx = 5)

        self.entry2 = Entry(self.right_frame, textvariable = self.category_type,
                            font = ('cambria', 11,), bg = 'Grey',width = 14)
        self.entry2.grid(row = 1, column = 1, sticky = W,pady = 5,padx = 5)

        # Buttons
        self.btn_1 = Button(self.right_frame,text = 'Add',font = ('cambria',12,'bold'),bg = 'SlateGrey',
                            activebackground='green', fg = 'white',width=12,height = 2,relief=RIDGE,
                            command = lambda :[add_main_accounts()])
        self.btn_1.grid(row = 3,column = 0,pady = 15)

        self.btn_2 = Button(self.right_frame, text = 'View', font = ('cambria', 12, 'bold'),
                            bg = 'SlateGrey',command=lambda :[display_account_types()],
                           activebackground='green', fg ='white', width=12, height = 2, relief = RIDGE)
        self.btn_2.grid(row = 3, column = 1)

# calling the class
app = Frontend(root)

root.mainloop()
user4157124
  • 2,809
  • 13
  • 27
  • 42
B _J
  • 9
  • 5
  • @Ayoub, if I remove the arguement 'self' from display_account_types(), it affects the function ,view_account_type(), which is at the Backend and the code wont run, I will still be missing the arguement 'self' from the view_account_type function. – B _J Nov 11 '22 at 20:58
  • Your indentiation changed halfway through. Your display_account_types is a function _within_ your main_account_function. If you want it to be a member function it needs to be on the same indent level as main_account. – Max Nov 12 '22 at 01:25
  • @Max I want the display_account function to within the main_account_function just as it has been displayed. – B _J Nov 12 '22 at 10:08
  • Nested functions almost never do what you want them to do. You probably want it to be part of the class, not part of the function. They can still share state via "self". – Max Nov 12 '22 at 14:06

2 Answers2

0

I think you should remove the self in display_account_types function like you did to the previous one.

delavega66
  • 855
  • 2
  • 23
  • 39
Ayoub
  • 1
  • 3
0

I got and answer to this question,

I just passed in the 'self' argument to the inner nested functions of the class as below and it worked.

 # functions
        def add_main_accounts(self):
            if self.category_id.get() == "" or self.category_type.get() == "":
                tkinter.messagebox.showinfo('All fields are required')
            else:
                Backend.insert_account_type(self,
                    self.category_id.get(),
                    self.category_type.get())   # category type unfilled

                tkinter.messagebox.showinfo('Entry successful')

        def display_account_types(self):
            self.trv.delete(*self.trv.get_children())
            for rows in Backend.view_account_type(self):
                self.trv.insert("", END, values = rows)
            return

        def get_account_type(e):
            self.selected_row = self.trv.focus()
            self.data = self.trv.item(self.selected_row)
            global row
            self.row = self.data["values"]

            """Grab items and send them to entry fields"""
            self.category_id.set(row[1])
            self.category_type.set(row[2])
B _J
  • 9
  • 5