2

I'm creating a GUI that interacts with a Postgresql database. The GUI displays all the contents of a certain table when the program launches. I have a button programmed to add/remove entries. The buttons work as when I checked the database, the entries are added to the database but I don't know how to refresh the TreeView in order for it to reflect the changes in the database.

My attempt to make it refresh is to clear (also to build) the TreeView is the _build_tree... code below:

def _build_tree(self):
            for i in self.tree.get_children():
                self.tree.delete(i)

            for col in self.header:
                self.tree.heading(col, text=col.title(),command=lambda c=col: self.sortby(self.tree, c, 0))
                # adjust the column's width to the header string
                self.tree.column(col,width=tkFont.Font().measure(col.title()))

            for item in self.content:
                self.tree.insert('', 'end', values=item)
                # adjust column's width if necessary to fit each value
                for ix, val in enumerate(item):
                    col_w = tkFont.Font().measure(val)
                    if self.tree.column(self.header[ix],width=None)<col_w:
                        self.tree.column(self.header[ix], width=col_w)

My complete code is below:

from tkinter import *
import tkinter.font as tkFont
import tkinter.ttk as ttk
import datetime
import psycopg2 as pg2


myFont = ('Impact',24)
myFontColor = 'red'

def check(): #to check if button works
    print ("It works!")

class Database:
    def __init__(self):
        self.conn = pg2.connect(database='inventory', user='loremipsum', password='loremipsum')
        self.cur = self.conn.cursor()
        self.timeNow = datetime.datetime.now()

    def view_rooms(self):
        self.cur.execute('''
                    SELECT * FROM rooms
                    ORDER BY room_id;
                    ''')
        return self.cur.fetchall()

    def add_room(self,roomID,roomName,floor):
        addRoom = '''
                INSERT INTO rooms (room_id,room_name,floor)
                VALUES ({},'{}',{});
                '''.format(roomID,roomName,floor)
        self.cur.execute(addRoom)
        self.conn.commit()

    def del_room(self,roomID):
        addRoom = '''
                DELETE FROM rooms
                WHERE room_id={};
                '''.format(roomID)
        self.cur.execute(addRoom)
        self.conn.commit()

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

database = Database()

class Page(Frame):
    def __init__(self, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

class RoomPage(Page):
    def __init__(self, *args, **kwargs): #create widgets
        Page.__init__(self, *args, **kwargs)

        Label(self,text="ROOM",font=myFont,fg=myFontColor).grid(row=0,column=0, sticky=W)
        Button(self,text="SEARCH",command=check).grid(row=0,column=1, sticky=W+E)

        self.header = ['Room ID','Room','Floor']
        self.content = database.view_rooms()

        self.tree=ttk.Treeview(self,columns=self.header, show="headings")
        vsb = ttk.Scrollbar(self,orient="vertical",command=self.tree.yview)
        hsb = ttk.Scrollbar(self,orient="horizontal",command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set,xscrollcommand=hsb.set)
        self.tree.bind('<ButtonRelease-1>',self.get_selected_row)
        self.tree.grid(column=0, row=1, columnspan=4, sticky='nsew')
        vsb.grid(column=4, row=1, sticky='ns')
        hsb.grid(column=0, row=2, columnspan=4, sticky='ew')

        self._build_tree()

        Button(self,text="ADD",command=AddRoom).grid(row=2,column=0,sticky=W+E)
        Button(self,text="REMOVE",command=self.deleteRoom).grid(row=2,column=1, sticky=W+E)
        Button(self,text="CLOSE",command=root.destroy).grid(row=2,column=3, sticky=W+E)

    def _build_tree(self):
        for i in self.tree.get_children():
            self.tree.delete(i)

        for col in self.header:
            self.tree.heading(col, text=col.title(),command=lambda c=col: self.sortby(self.tree, c, 0))
            # adjust the column's width to the header string
            self.tree.column(col,width=tkFont.Font().measure(col.title()))

        for item in self.content:
            self.tree.insert('', 'end', values=item)
            # adjust column's width if necessary to fit each value
            for ix, val in enumerate(item):
                col_w = tkFont.Font().measure(val)
                if self.tree.column(self.header[ix],width=None)<col_w:
                    self.tree.column(self.header[ix], width=col_w)

    def sortby(self,tree, col, descending):
        """sort tree contents when a column header is clicked on"""
        # grab values to sort
        data = [(tree.set(child, col), child) \
            for child in tree.get_children('')]
        # now sort the data in place
        data.sort(reverse=descending)
        for ix, item in enumerate(data):
            tree.move(item[1], '', ix)
        # switch the heading so it will sort in the opposite direction
        tree.heading(col, command=lambda col=col: sortby(tree, col, \
            int(not descending)))

    def get_selected_row(self,event):
        selection = self.tree.item(self.tree.selection())
        self.selected_tuple=selection['values'][0]

    def openRoom(self,event):
        index=self.roomList.curselection()[0]
        self.selected_tuple=self.roomList.get(index)[0]
        print (self.selected_tuple)

    def deleteRoom(self):
        database.del_room(self.selected_tuple)
        self.clear()
        self.build()

class AddRoom:
    def __init__(self, *args, **kwargs): #create widgets
        window = Toplevel(root)
        window.title("Room Details")

        roomDetailsLabel = Label (window,text="Room Details",font=myFont,fg=myFontColor).grid(row=0,column=0, sticky=W,columnspan=2)

        roomNumLabel = Label(window,text="Room ID").grid(row=1,column=0, sticky=E)
        self.roomNumText = StringVar()
        roomNameEntry = Entry(window,textvariable=self.roomNumText,width=30).grid(row=1,column=1,sticky=W)

        roomNameLabel = Label(window,text="Room Name").grid(row=2,column=0, sticky=E)
        self.roomNameText = StringVar()
        roomNameEntry = Entry(window,textvariable=self.roomNameText,width=30).grid(row=2,column=1,sticky=W)

        floorLabel = Label(window,text="Floor").grid(row=3,column=0, sticky=E)
        self.floorText = StringVar()
        floorEntry = Entry(window,textvariable=self.floorText,width=30).grid(row=3,column=1,sticky=W)

        Button(window,text="SAVE",command=self.add_room).grid(row=4,column=0,sticky=W+E)
        Button(window,text="CLOSE",command=window.destroy).grid(row=4,column=1,sticky=W+E)

    def add_room(self):
        database.add_room(self.roomNumText.get(),self.roomNameText.get(),self.floorText.get())
        p1._build_tree()

class MainView(Frame):
    def __init__(self, *args, **kwargs):
        global p1
        Frame.__init__(self, *args, **kwargs)
        p1 = RoomPage(self)

        buttonframe = Frame(self)
        container = Frame(self)
        buttonframe.pack(side="top", fill="x", expand=False)
        container.pack(side="top", fill="both", expand=True)

        p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)

        p1.show()

if __name__ == "__main__": #main loop
    root = Tk()
    root.title('Inventory System')
    root.configure(bg="#BDE9EB")
    parent = Frame(root, padx=10, pady=10)
    parent.pack(fill=BOTH, expand=True)
    main = MainView(parent)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("600x350")
    root.mainloop()

How do you refresh the TreeView to reflect the changes made in the database?

3
  • with this functiondef _build_tree(self) what do you get after refreshing Commented Apr 10, 2018 at 8:53
  • Looks like a candidate for an Observer-Pattern or Model-View-Pattern. Commented Apr 10, 2018 at 10:00
  • I get the same records when the code was first ran. Meaning reocrds that I added/deleted will not appear in the TreeView. I even tried binding the function to a button and it still produces same thing. But when I close the program and run it again, the new records show and the deleted records are gone. Commented Apr 11, 2018 at 2:38

1 Answer 1

2

Hello seems like the problem you have encountered is like mine.

You are correct when you call the get.children() after that what you will do is call the database again. Here is my code, i hope you will get this.

def _build_tree(self):
    cursor=db.cursor(buffered=True)
    cursor.execute("SELECT   ")
    result = cursor.fetchall()
    for i in self.tree.get_children():
           self.tree.delete(i)
    for i in result:
           self.tree.insert('', 'end', values=(i[0],i[2]..)
Sign up to request clarification or add additional context in comments.

1 Comment

always remember that call the database again. Co'z if you will not call it the function can't access it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.