Python Forum
tkinter - update/refresh treeview
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
tkinter - update/refresh treeview
#1
I've got a treeview widget that is supplied data from an sql database.

I've been trying all day to make it so when I add a row to the database that the treeview instantly updates. I can't even begin to explain what I've tried so far but it's mostly based around trying to re-run def populate_tab_tree from the end of def on_save_button. I've also tried pasting the code into the end of my on_save_button method.

Needless to say, it's failed every time.

Can anyone point me in the right direction please.

Thank you

###### TO DO #######
"""
Simpligy the way buttons are added. 
Scrollbar not working
update treeview when new contact added to database
id row (use rowid? treeview messed up)
edit contact in database (select record, insert into entry box)
delete contact in databse
"""
#####################


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

### Create tkinter window ##
root = Tk()
root.title("Bookkeeping")
root.geometry("1024x768") 
#root.attributes("-fullscreen",1)

### Add a Notebook to window ###
notebook = Notebook(root)
notebook.pack(fill="both", expand=1, pady=15)

### Class to add tabs to the notebook. Methods allow to add a Treeview, populate treeview ###
class Tab:
    def __init__(self, tab):
        self.tab = tab

        self.tab = Frame(notebook)
        self.tab.pack(fill="both", expand=1)
        notebook.add(self.tab, text=str(tab)) 

    def tab_tree(self, column_names):
        self.column_names = column_names    
        
        self.treeview_frame = Frame(self.tab)
        self.treeview_frame.pack(fill="both", expand=1)
        
        self.tree_scroll = Scrollbar(self.treeview_frame)
        self.tree_scroll.pack(side=RIGHT, fill=Y) 
        self.tab_tree = Treeview(self.treeview_frame, yscrollcommand=self.tree_scroll.set, selectmode="extended") 
        self.tab_tree.pack(fill="both", expand=YES)        
        
        self.tab_tree['columns'] = column_names
        self.tab_tree.column("#0", width=0, stretch=NO)
        self.tab_tree.heading("#0", text="")
        for name in column_names:
            self.tab_tree.column(name, minwidth=25, width=50) 
            self.tab_tree.heading(name, text=name)                  
    
    def populate_tab_tree(self, table, columns):
        self.table = table
        self.columns = columns

        conn = sqlite3.connect('Bookkeeping_Database.sqlite3')
        cur = conn.cursor()
        cur.execute("CREATE TABLE IF NOT EXISTS " + self.table + " (" + " TEXT, ".join(self.columns) +" TEXT)")
        cur.execute("SELECT * FROM " + self.table)
        records = cur.fetchall()     
        conn.commit()
        conn.close()          

        count=0
        for row in records:
            self.tab_tree.insert(parent='', index='end', iid=count, text='', values=row)
            count+=1            
               
    
### Class to create contact tab ###
class Create_contact_tab:
    def __init__ (self, tab_name, new_contact_button_name, column_names):
        self.tab_name = tab_name
        self.new_contact_button_name = new_contact_button_name
        self.tab_name = tab_name 
        self.column_names = column_names

        self.contact_tab = Tab(self.tab_name)
        self.contact_tab.tab_tree(column_names)
        self.contact_tab.populate_tab_tree(tab_name, column_names)   
        #self.select_record()     

        self.new_contact_button = Button(self.contact_tab.tab, text=(self.new_contact_button_name), command=self.new_contact_window)
        self.new_contact_button.pack(side=LEFT, padx=10, pady=10) 

        self.edit_contact_button = Button(self.contact_tab.tab, text="Edit", command=self.edit_contact_window)
        self.edit_contact_button.pack(side=LEFT, padx=10, pady=10) 

        self.delete_contact_button = Button(self.contact_tab.tab, text="Delete")
        self.delete_contact_button.pack(side=LEFT, padx=10, pady=10)
    
    def new_contact_window(self):
        self.new_contact_window = New_contact_window(self.tab_name) 
        self.new_contact_window.create_entry_boxes(self.column_names)     
        self.new_contact_window.save_button()
        self.new_contact_window.close_button()

    def edit_contact_window(self):
        self.edit_contact_window = Edit_contact_window(self.tab_name)
        self.edit_contact_window.create_entry_boxes(self.column_names)  
        self.edit_contact_window.save_button()
        self.edit_contact_window.close_button()
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""        
    def select_record(self):
        selected = self.contact_tab.tab_tree.focus()
        values = self.contact_tab.tab_tree(selected, 'values')
        print(values)
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

### Class to create new contact window ###
class New_contact_window:
    def __init__(self, tab_name):
        self.window = tab_name
        self.table_name = tab_name

        self.window = Toplevel()
        self.window.title("Add New " + self.table_name)
        
        self.frame = Frame(self.window)
        self.frame.pack(fill="both", expand=1, pady=10)
        
        self.detail_name_dictionary = {}
        self.detail_name_list_keys = []
    
    def create_entry_boxes(self, column_names):      
        self.column_names = column_names

        row=1
        column=1
        for detail_name in self.column_names:
            self.label = Label(self.frame, text=detail_name) 
            self.label.grid(row=row, column=column, padx=10) 
            column +=1
            self.entry_box = Entry(self.frame) 
            self.entry_box.grid(row=row, column=column, padx=10)
            row +=1
            column -=1

            self.detail_name_list_keys.append(detail_name) 
            self.detail_name_dictionary[detail_name] = self.entry_box                

    def save_button(self):
        self.save_button = Button(self.frame, text="Save", command=self.on_save_button)
        self.save_button.grid(row=11, column=2, padx=10, pady=10) 
    
    def on_save_button(self):
        inputted_data=[]
        values = []
        if len(self.entry_box.get()) == 0:
            pass
        else:
            for detail_name in self.detail_name_list_keys:
                entry_value = self.detail_name_dictionary[detail_name].get() 
                inputted_data.append(entry_value)
                values.append("?")
            inputted_data=tuple(inputted_data)
            values = ('(' + str(', '.join([str(i[0]) for i in values])) + ')')

            conn = sqlite3.connect('Bookkeeping_Database.sqlite3')
            cur = conn.cursor()
            cur.execute("CREATE TABLE IF NOT EXISTS " + self.table_name + " (" + " TEXT, ".join(self.detail_name_list_keys) +" TEXT)")
            cur.execute("INSERT INTO "+ self.table_name +"(" + ", ".join(self.detail_name_list_keys) + ") VALUES" + values + "", inputted_data,)
            conn.commit()
            conn.close()       

            saved_label = Label (self.frame, text="Saved") 
            saved_label.grid(row=12, column=2)

            self.create_entry_boxes(column_names)

    def close_button(self):
        self.close_button = Button(self.frame, text="Close", command=self.window.destroy)
        self.close_button.grid(row=11, column=1, padx=10, pady=10)    

### Class to create contact edit window ###
class Edit_contact_window(New_contact_window):
    def __init__ (self, tab_name):
        self.window = tab_name
        self.table_name = tab_name

        self.window = Toplevel()
        self.window.title("Edit " + self.table_name)
        
        self.frame = Frame(self.window)
        self.frame.pack(fill="both", expand=1)
        
        self.detail_name_dictionary = {}
        self.detail_name_list_keys = []    

### Add contact tabs ###
column_names = [    "ID",
                    "Company",
                    "Name",
                    "Street",
                    "Town",
                    "City",
                    "County",
                    "Postcode", 
                    "Email", 
                    "Phone", 
                    ]

customer_tab = Create_contact_tab("Customers", "Add New Customer", column_names)


vendor_tab = Create_contact_tab("Vendors", "Add New Vendor", column_names)

root.mainloop()
Reply
#2
I am going to run your code and see what is up.
Reply
#3
Maybe add a function for refreshing the rows when you switch to other tab and back again.
Reply
#4
The View class adds an expose event to Frame. The expose_event() method is called when the View becomes visible. In the example I use this to update a control in the View to some global value shared by all the views. Type a value in the entry box and <Enter>. If you change to a different tab the entry widget is updated to reflect the shared value.
import tkinter as tk
from tkinter import ttk

class View(tk.Frame):
    """A frame with an expose event"""
    shared_text = ''

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.bind('<Expose>', self.expose_event)

        self.local_text = tk.StringVar()
        self.entry = tk.Entry(self, textvariable=self.local_text)
        self.entry.pack()
        self.entry.bind('<Return>', self.set_value)
    
    def set_value(self, event):
        """Called when enter key is pressed in entry widget"""
        View.shared_text = self.local_text.get()

    def expose_event(self, event):
        """Called when I become visible"""
        self.local_text.set(View.shared_text)

root = tk.Tk()
notebook = ttk.Notebook(root)
notebook.pack(fill=tk.BOTH, expand=tk.YES)
for i in range(5):
    notebook.add(View(notebook), text=str(i))
root.mainloop()
This solution only works for data that may have changed while the View was not visible and must be updated when it becomes visible. This will work great for something like a notebook if the notebook is self contained; i.e. only pages in the notebook can change values displayed in other pages and only one page can be visible at a time. It may not be applicable to your problem.
Reply
#5
Thank you for your replies.

I ended up having to enter the 'insert' code from populate_tab_tree each time I needed it instead of reusing the method, and setting count to global so I'm not trying to overwrite previous inserts.

I also had to clear the table before inserting.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyQt] Refresh x-labels in matplotlib animation widget JohnT 5 925 Apr-23-2021, 07:40 PM
Last Post: JohnT
  [Tkinter] acceleration of data output in treeview tkinter Vladimir1984 4 1,003 Nov-21-2020, 03:43 PM
Last Post: Vladimir1984
  Want to dynamically update numbers using tkinter in pygame script k0gane 0 713 Feb-09-2020, 09:01 AM
Last Post: k0gane
  Refresh image in label after every 1s using simple function jenkins43 1 3,561 Jul-28-2019, 02:49 PM
Last Post: Larz60+
  Unable to update or refresh label text in tkinter jenkins43 3 3,818 Jul-24-2019, 02:09 PM
Last Post: Friend
  Tkinter - Make changes to graph and update it adriancovaci 0 4,591 Apr-08-2019, 09:02 AM
Last Post: adriancovaci
  [Tkinter] Tkinter timetabl using treeview mntfr 3 1,545 Feb-05-2019, 09:36 PM
Last Post: Larz60+
  sQlite3 output to tkinter treeview - how do I set / increase width of the output? dewijones67 5 3,890 Jan-23-2019, 08:45 AM
Last Post: Larz60+
  Tkinter refresh eduardoforo 4 8,177 Nov-14-2018, 09:35 PM
Last Post: woooee
  [Tkinter] Label doesn't refresh jollydragon 7 4,412 Jul-13-2018, 05:55 AM
Last Post: jollydragon

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020