2

I have a ttk.Notebook and each tab contains a ttk.Treeview. All treeviews have the same columns but contain different items, like in the code below.

import tkinter as tk
from tkinter import ttk

root = tk.Tk()

notebook = ttk.Notebook(root)
notebook.pack()

tree1 = ttk.Treeview(notebook, columns=['a', 'b', 'c'])
tree1.insert('', 'end', text='item1', values=('a1', 'b1', 'c1'))
tree2 = ttk.Treeview(notebook, columns=['a', 'b', 'c'])
tree2.insert('', 'end', text='item2', values=('a2', 'b2', 'c2'))
tree2.insert('', 'end', text='item2', values=('a2', 'b2', 'c2'))

notebook.add(tree1, text='Tab 1')
notebook.add(tree2, text='Tab 2')

root.mainloop()

I would like all trees to always have the same column widths. So, for instance, when the user resizes the column 'a' of tree1, the column 'a' of tree2 should be resized too.

I know I can get the size of a column with tree1.column('a', 'width') and set it with tree2.column('a', width=300).

But how can I detect that the size of a column has changed?

I have checked that the treeview <Configure> event is not triggered by a column resizing.

j_4321
  • 15,431
  • 3
  • 34
  • 61
  • 2
    If you care just for user interaction, you can bind a call back to `` event and check `identify_region(event.x, event.y)`. If it returns `'separator'` - get `iid` of the column via `identify_column(event.x)` and `width` after that. Create a function, wich would iterate over all columns of a specified widget with specified width. If you change `width` programmatically - just call that function. If it changes via user - `` should handle it. – CommonSense Dec 07 '17 at 13:26
  • 1
    Yeah, it looks like a good idea. However, I don't know how hard it would hit a perfomance and how responsive a `treeview` would be, obviously it depends on implementation. However, another option is to bind to `` with same logic to prevent a possible perfomance issue. – CommonSense Dec 07 '17 at 13:42
  • Might be an interesting thing to solve this with `ttk::treeview::Press`. – Nae Dec 24 '17 at 01:38

1 Answers1

2

Following CommonSense suggestions, I have made a binding on <ButtonRelease-1> to check if a column has been resized. If tree.identify_region(event.x, event.y) is 'separator' then there was a resizing. Then I need to identify the columns on both sides of the separator. tree.identify_column(event.x) gives me the column on the left in the form '#<column number>' and from it I can get the id of the column on the right. Finally, I execute the function that resize the columns in all trees.

import tkinter as tk
from tkinter import ttk

root = tk.Tk()


def on_click_release(event):
    tree = event.widget
    if tree.identify_region(event.x, event.y) == 'separator':
        left_column = tree.identify_column(event.x)
        right_column = '#%i' % (int(tree.identify_column(event.x)[1:]) + 1)
        width_l = tree.column(left_column, 'width')
        width_r = tree.column(right_column, 'width')
        for tree2 in trees:
            if tree2 != tree:
                tree2.column(left_column, width=width_l)
                tree2.column(right_column, width=width_r)


notebook = ttk.Notebook(root)
notebook.pack()

trees = [ttk.Treeview(notebook, columns=['a', 'b', 'c']) for i in range(4)]

for i, tree in enumerate(trees):
    tree.bind('<ButtonRelease-1>', on_click_release)
    notebook.add(tree, text='Tab %i' % i)

root.mainloop()

EDIT: I realized that the above method does not work if we move the column separator too quickly (tree.identify_region(event.x, event.y) does not return 'separator'). So I have found a different method: When the user changes tab, then the width of each column of the current tab is set to the width of the corresponding column of the previously visible tab.

import tkinter as tk
from tkinter import ttk


def tab_changed(event):
    global current_tab
    tab = notebook.index('current')  # get newly visible tab number
    tree1 = trees[current_tab]  # get previously visible tree
    tree2 = trees[tab]   # get newly visible tree
    cols = ('#0', ) + tree1.cget('columns')  # tuple of all columns
    for column in cols:
        tree2.column(column, width=tree1.column(column, 'width'))
    current_tab = tab


root = tk.Tk()
notebook = ttk.Notebook(root)
notebook.pack()

trees = [ttk.Treeview(notebook, columns=['a', 'b', 'c']) for i in range(4)]
current_tab = 0  # store currently visible tab number

for i, tree in enumerate(trees):
    notebook.bind('<<NotebookTabChanged>>', tab_changed)
    notebook.add(tree, text='Tab %i' % i)

root.mainloop()
j_4321
  • 15,431
  • 3
  • 34
  • 61