Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Format individual cell/item rather than entire row in tkinter ttk treeview

I am currently using a function to display a pandas dataframe in a spreadsheet style format. I would like to be able to add some functionality to format individual cells of the treeview based on their content e.g. if they contain substring 'X' or if their value is higher than Y.

The update function currently implemented is as follows:

   def updateTree(self, dataframe):
    '''
    Updates the treeview with the data in the dataframe
    parameter
    '''
    #Remove any nan values which may have appeared in the dataframe parameter
    df = dataframe.replace(np.nan,'', regex=True)

    #Currently displayed data
    self.treesubsetdata = dataframe

    #Remove existing items
    for item in self.tree.get_children(): self.tree.delete(item)
    #Recreate from scratch the columns based on the passed dataframe
    self.tree.config(columns= [])
    self.tree.config(columns= list(dataframe.columns))

    #Ensure all columns are considered strings and write column headers
    for col in dataframe.columns:
        self.tree.heading(col,text=str(col))

    #Get number of rows and columns in the imported script
    self.rows,self.cols = dataframe.shape

    #Populate data in the treeview
    for row in dataframe.itertuples():
        self.tree.insert('', 'end',values = tuple(row[1:]))

    #Minimise first column
    self.tree.column('#0',width=0)
    self.tree.update()

Can anyone confirm that you can in fact edit an individual cell in a treview?

If yes are there any ideas as to how this could be implemented?

like image 417
user3535074 Avatar asked Mar 08 '17 09:03

user3535074


People also ask

What is IID in tkinter Treeview?

The iid argument stands for item identifier which is unique for each item, and you can give it the value you want.

What is the difference between tkinter and tkinter TTK?

Tkinter widgets are used to add Buttons, Labels, Text, ScrollBar, etc., however, tkinter. ttk supports a variety of widgets as compared to tkinter widgets. Tkinter. ttk doesn't support Place, Pack() and Grid(), thus it is recommended to use tkinter widget with ttk.

How do I set Treeview size?

To set the row height of the Treeview widget, you can create an instance of ttk themed widget where you can specify the rowheight property. The rowheight property will add internal padding to each row in the table.

How do I edit a Treeview in Python?

The Treeview widget items can be edited and deleted by selecting the item using tree. selection() function. Once an item is selected, we can perform certain operations to delete or edit the item.


1 Answers

It's not possible to set the style of individual cells in Treeview; only entire rows can use the tag attribute.

If you just want a table of values then I'd recommend just using ttk.Label widgets, which you can format in a huge number of ways. For example:

import Tkinter as tk
import ttk
import pandas as pd
from random import randrange

PADDING = dict(padx=3, pady=3)
class GridView(tk.Frame):
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.labels = []
        style = ttk.Style()
        style.configure("red.TLabel", background='red')
        style.configure("green.TLabel", background='green')
        style.configure("header.TLabel", font = '-weight bold')

    def set(self, df):
        self.clear()
        for col, name in enumerate(df.columns):
            lbl = ttk.Label(self, text=name, style='header.TLabel')
            lbl.grid(row=0, column=col, **PADDING)
            self.labels.append(lbl)

        for row, values in enumerate(df.itertuples(), 1):
            for col, value in enumerate(values[1:]):
                lbl = ttk.Label(self, text=value, style=self.get_style(value))
                lbl.grid(row=row, column=col, **PADDING)
                self.labels.append(lbl)

    @staticmethod
    def get_style(value):
        if value > 70:
            return "red.TLabel"
        elif value < 30:
            return "green.TLabel"
        else:
            return None

    def clear(self):
        for lbl in self.labels:
            lbl.grid_forget()
        self.labels = []

class GUI(tk.Frame):
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.table = GridView(self)
        self.table.pack()
        btn = ttk.Button(self, text="populate", command=self.populate)
        btn.pack()
        btn = ttk.Button(self, text="clear", command=self.table.clear)
        btn.pack()

    def populate(self):
        self.table.set(new_rand_df())

def main():
    root = tk.Tk()
    win = GUI(root)
    win.pack()
    root.mainloop()

def new_rand_df():
    width = 5
    height = 5
    return pd.DataFrame([[randrange(100) for _ in range(width)] for _ in range(height)], columns = list('abcdefghijklmnopqrstuvwxyz'[:width]))

if __name__ == '__main__':
    main()
like image 190
Novel Avatar answered Oct 22 '22 11:10

Novel