Steve
Steve

Reputation: 43

function call from a function to a function within a class fails

I'm trying to setup a program where my tkinter GUI functions are in a class and my database functions are in another class. I have a function external to both classes that fails when I try to call a function within the DB class. Can you help me resolve this error? Should both my GUI and any database be in separate functions or is that a poor design. The attached code is a stripped down version to illustrates my issue. Clicking the "View all" button generates the error.

import sqlite3
from tkinter import *
from tkinter import messagebox

class DB:
    def __init__(self):
        self.conn = sqlite3.connect("mybooks.db")
        self.cur = self.conn.cursor()
        self.cur.execute(
            "CREATE TABLE IF NOT EXISTS book (id INTEGER PRIMARY KEY, title TEXT, author TEXT, isbn INTEGER)")
        self.conn.commit()

    def __del__(self):
        self.conn.close()

    def view(self):
        self.cur.execute("SELECT * FROM book")
        rows = cur.fetchall()
        return rows

def view_command():
    # there is a problem with the next line
    # when rows=DB.view() error is TypeError: view() missing 1 required positional argument: 'self'
    # when rows=DB.view(self) error is NameError: name 'self' is not defined
    rows=DB.view(self)
    for row in rows:
        print(row)

class App_GUI():   # create the main window
    def __init__(self, master):                         
        self.master = master
        self.master.title("My Books")       

        self.master.l1 = Label(self.master, text="Title")
        self.master.l1.grid(row=0, column=0)

        self.master.l2 = Label(self.master, text="Author")
        self.master.l2.grid(row=0, column=2)

        self.master.l3 = Label(self.master, text="ISBN")
        self.master.l3.grid(row=1, column=0)

        self.master.title_text = StringVar()
        self.master.e1 = Entry(self.master, textvariable=self.master.title_text)
        self.master.e1.grid(row=0, column=1)

        self.master.author_text = StringVar()
        self.master.e2 = Entry(self.master, textvariable=self.master.author_text)
        self.master.e2.grid(row=0, column=3)

        self.master.isbn_text = StringVar()
        self.master.e3 = Entry(self.master, textvariable=self.master.isbn_text)
        self.master.e3.grid(row=1, column=1)

        self.master.list1 = Listbox(self.master, height=6, width=35)
        self.master.list1.grid(row=2, column=0, rowspan=6, columnspan=2)

        self.master.sb1 = Scrollbar(self.master)
        self.master.sb1.grid(row=2, column=2, rowspan=6)

        self.master.list1.configure(yscrollcommand=self.master.sb1.set)
        self.master.sb1.configure(command=self.master.list1.yview)

        self.master.b1 = Button(self.master, text="View all", width=12, command=view_command)
        self.master.b1.grid(row=2, column=3)

        self.master.b6 = Button(self.master, text="Close", width=12, command=self.master.destroy)
        self.master.b6.grid(row=7, column=3)
        return

###############################
# Program Main                #
###############################
def main():
    db = DB()
    root = Tk()         
    def on_closing():
        dd = db
        if messagebox.askokcancel("Quit", "Do you want to close the application"): # ask the user if he/she wants to close the application
            root.destroy()
            del dd
    root.protocol("WM_DELETE_WINDOW", on_closing) # catch the user closing the window
    app = App_GUI(root)                     # creation of an instance
    root.mainloop()                         # tkinter mainloop

if __name__ == '__main__':
    main()
````

Upvotes: 1

Views: 40

Answers (2)

Steve
Steve

Reputation: 43

I figured it out! In addition to your changes, I had to remove 'self' from rows=db.view(). Thanks for your help! Revised code:

import sqlite3
from tkinter import *
from tkinter import messagebox

class DB:
    def __init__(self):
        self.conn = sqlite3.connect("mybooks.db")
        self.cur = self.conn.cursor()
        self.cur.execute(
            "CREATE TABLE IF NOT EXISTS book (id INTEGER PRIMARY KEY, title TEXT, author TEXT, isbn INTEGER)")
        self.conn.commit()

    def __del__(self):
        self.conn.close()

    def view(self):
        self.cur.execute("SELECT * FROM book")
        rows = self.cur.fetchall()
        return rows

def view_command(db):
    rows=db.view()
    for row in rows:
        print(row)

class App_GUI():   # create the main window
    def __init__(self, master, db):                         
        self.master = master
        self.master.title("My Books")       

        self.master.l1 = Label(self.master, text="Title")
        self.master.l1.grid(row=0, column=0)

        self.master.l2 = Label(self.master, text="Author")
        self.master.l2.grid(row=0, column=2)

        self.master.l3 = Label(self.master, text="ISBN")
        self.master.l3.grid(row=1, column=0)

        self.master.title_text = StringVar()
        self.master.e1 = Entry(self.master, textvariable=self.master.title_text)
        self.master.e1.grid(row=0, column=1)

        self.master.author_text = StringVar()
        self.master.e2 = Entry(self.master, textvariable=self.master.author_text)
        self.master.e2.grid(row=0, column=3)

        self.master.isbn_text = StringVar()
        self.master.e3 = Entry(self.master, textvariable=self.master.isbn_text)
        self.master.e3.grid(row=1, column=1)

        self.master.list1 = Listbox(self.master, height=6, width=35)
        self.master.list1.grid(row=2, column=0, rowspan=6, columnspan=2)

        self.master.sb1 = Scrollbar(self.master)
        self.master.sb1.grid(row=2, column=2, rowspan=6)

        self.master.list1.configure(yscrollcommand=self.master.sb1.set)
        self.master.sb1.configure(command=self.master.list1.yview)

        self.master.b1 = Button(self.master, text="View all", width=12, command=lambda : view_command(db))
        self.master.b1.grid(row=2, column=3)

        self.master.b6 = Button(self.master, text="Close", width=12, command=self.master.destroy)
        self.master.b6.grid(row=7, column=3)
        return

###############################
# Program Main                #
###############################
def main():
    db = DB()
    root = Tk()         
    def on_closing():
        dd = db
        if messagebox.askokcancel("Quit", "Do you want to close the application"): # ask the user if he/she wants to close the application
            root.destroy()
            del dd
    root.protocol("WM_DELETE_WINDOW", on_closing) # catch the user closing the window
    app = App_GUI(root, db)                     # creation of an instance
    root.mainloop()                         # tkinter mainloop

if __name__ == '__main__':
    main()

Upvotes: 1

quamrana
quamrana

Reputation: 39354

You need to pass db to App_GUI and then on to the function:


def view_command(db):
    rows = db.view()
    for row in rows:
        print(row)

class App_GUI():   # create the main window
    def __init__(self, master, db):  
        # other stuff elided ...
        self.master.b1 = Button(self.master, text="View all", width=12, command=lambda : view_command(db))

...
def main():
    db = DB()
    # other stuff elided
    app = App_GUI(root, db)

edit: forgot to remove self.

Upvotes: 1

Related Questions