Tkinter Treeview doesn't give indication for hidden characters

Viewed 435

The text is "This is too long text". As you can see the view provides an option to expand horizontally but there is not indication that there are more characters.

I need some indication for the user that there are more characters in the cell. i.e showing "...".

enter image description here

This is the code:

from tkinter import ttk
import tkinter as tk

win = tk.Tk()
win.resizable(width=0, height=0)

tree = ttk.Treeview(win, selectmode='browse')
tree.grid(row=0, column=0)

vsb = ttk.Scrollbar(win, orient="horizontal", command=tree.xview)
vsb.grid(row=1, column=0, sticky=tk.W + tk.E + tk.N + tk.S)
tree.configure(xscrollcommand=vsb.set)

vsb = ttk.Scrollbar(win, orient="vertical", command=tree.yview)
vsb.grid(row=0, column=1, sticky=tk.W + tk.E + tk.N + tk.S)
tree.configure(yscrollcommand=vsb.set)

tree["columns"] = ("1", "2")
tree['show'] = 'headings'
tree.column("1", anchor='c')
tree.column("2", width=100, anchor='c')
tree.heading("1", text="Col 1")
tree.heading("2", text="Col 2")
tree.insert("", 'end', text="L4", values=("This text is too long","Short text"))

win.mainloop()
1 Answers

Update:

Turns out we can bind '<ButtonRelease-1>' to the treeview as noted on this post: how-to-detect-resizing-of-ttk-treeview-column that @stovfl has pointed out in the comments. So I have updated my answer with less overhead :D.

I created a method that will check to see of the column width has changed and then if it has then calculate each row to see if we need to add ... to the end.

This is accomplished with ImageFont from PIL thought for some reason there seams to be a size difference between Treeview font and PIL font. After some testing it appears that any font size you set in the style for the Treeview just add 5 to the PIL font and it should calculate correctly.

import tkinter as tk
import tkinter.ttk as ttk
from PIL import ImageFont


track_data = [[('This text is too long', 'Short text'), 'This text is too long'],
              [('This text is toooooooo long', 'Short text'), 'This text is toooooooo long'],
              [('This text is longer than most others', 'Short text'), 'This text is longer than most others'],
              [('This text is short', 'Short text'), 'This text is short']]


def add_to_tree_list(long_text, short_text, top):
    track_data.append([(long_text.get(), short_text.get()), long_text.get()])
    top.destroy()
    update_text()


def pop_list(ndex):
    track_data.pop(ndex)


def remove_row_from_list():
    top = tk.Toplevel(win)
    build_top_frame(top)
    update_text()


def build_top_frame(top):
    row_button_list = []
    for child in top.winfo_children():
        child.destroy()
    frame = tk.Frame(top)
    frame.pack()
    for ndex, sub_list in enumerate(track_data):
        row_button_list.append([tk.Button(frame, text='Remove',
                                          command=lambda n=ndex: (pop_list(n), update_text(), build_top_frame(top))),
                                tk.Label(frame, text='Row {}:  {}'.format(ndex + 1, sub_list[1]))])
        row_button_list[-1][0].grid(row=ndex, column=0)
        row_button_list[-1][1].grid(row=ndex, column=1, sticky='w')


def top_for_new_row():
    top = tk.Toplevel(win)
    tk.Label(top, text='Add long text: ').grid(row=0, column=0)
    tk.Label(top, text='Add short text: ').grid(row=1, column=0)
    e1 = tk.Entry(top)
    e2 = tk.Entry(top)
    e1.grid(row=0, column=1)
    e2.grid(row=1, column=1)
    tk.Button(top, text='Submit', command=lambda: add_to_tree_list(e1, e2, top)).grid(row=2, column=0)
    tk.Button(top, text='Cancel', command=top.destroy).grid(row=2, column=1)


def clear_and_load(data):
    tree.delete(*tree.get_children())
    for sub_list in data:
        tree.insert('''''', 'end', text='L4', values=sub_list[0])


def update_text(_=None):
    global old_col_width, old_track_data_len
    col_width = tree.column('1')['width']
    if col_width != old_col_width or old_track_data_len != len(track_data):
        old_col_width = col_width
        new_track_data = []
        for text in track_data:
            font = ImageFont.truetype("arial.ttf", 17)
            size = font.getsize(text[0][0])
            previous_long_text = ''
            new_long_text = ''
            if size[0] > col_width:
                for char in text[0][0]:
                    new_long_text = '{}{}'.format(new_long_text, char)
                    new_size = font.getsize('{}{}'.format(new_long_text, '...'))[0]
                    if new_size < col_width:
                        previous_long_text = new_long_text
                    else:
                        new_track_data.append([('{}{}'.format(previous_long_text, '...'), text[0][1]), ''])
                        break
            else:
                new_track_data.append(text)
        clear_and_load(new_track_data)
    old_track_data_len = len(track_data)


win = tk.Tk()
win.columnconfigure(0, weight=1)
old_col_width = 200
old_track_data_len = 0
win.resizable(width=0, height=0)
style = ttk.Style()
style.configure('Treeview', font=('arial', 12))
tree = ttk.Treeview(win)
tree.grid(row=0, column=0)
tree.bind('<ButtonRelease-1>', update_text)

vsb = ttk.Scrollbar(win, orient='horizontal', command=tree.xview)
vsb.grid(row=1, column=0, sticky='nsew')
tree.configure(xscrollcommand=vsb.set)

vsb = ttk.Scrollbar(win, orient='vertical', command=tree.yview)
vsb.grid(row=0, column=1, sticky='nsew')
tree.configure(yscrollcommand=vsb.set)
btn_frame = tk.Frame(win)
btn_frame.grid(row=2, column=0, columnspan=2, sticky='ew')
btn_frame.columnconfigure(0, weight=1)
btn_frame.columnconfigure(1, weight=1)
tk.Button(btn_frame, text='Add Row!', command=top_for_new_row).grid(row=0, column=0, sticky='ew')
tk.Button(btn_frame, text='Remove Row!', command=remove_row_from_list).grid(row=0, column=1, sticky='ew')

columns = ('1', '2')
tree['columns'] = columns
tree['show'] = 'headings'
tree.column('1', width=200, stretch=True, anchor='w')
tree.column('2', width=100, anchor='w')
tree.heading('1', text='Col 1')
tree.heading('2', text='Col 2')

clear_and_load(track_data)
update_text()
win.mainloop()

Results:

enter image description here

Adding new line:

enter image description here

Removing lines:

enter image description here

Related