简体   繁体   中英

Refresh Python tkinter TreeView

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?

It's not a refresh, but You could extend the methot that inserts the new value to the database, to insert it also into the Treeview.

What does the program do if you just run the proposed _build_tree method?

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]..)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM