How to disable manual resizing of Tkinter's Treeview column?
Asked Answered
L

5

6

Since I can't horizontally scroll Treeview column due to what appears to be Tk/Tkinter limitation, I want to make it sticky so it is attached to the frame.

The issue is that user can manually resize Treeview column which can mess up my interface in a certain way. Is it possible to disable such functionality?

Note the size of column header.

Note the size of the column header.

User can drag mouse to resize column. I want to disable this.

User can drag mouse to resize column. I want to disable this.

Setting minwidth to a certain value prevents column from shrinking, but it is still possible to resize it to a larger width. I suppose I can react to changing width and just revert it to original, but there has to be a better way to do it.

Laryngotomy answered 27/7, 2017 at 18:25 Comment(0)
D
14

The following has only been tested on Windows, other OS's may vary.

For any future readers, since Tk 8.5, Treeviews have an identify_region method that accepts a screen position (x,y) and will return a string corresponding to the region of the treeview those coordinates occupy.

One of the return values is "separator".

I've used this to catch double-click events on the separator to auto-size columns, but you could also use it to catch single-click events and block them.

For example:

def handle_click(event):
    if treeview.identify_region(event.x, event.y) == "separator":
        return "break"

#...

treeview.bind('<Button-1>', handle_click)

This has the advantage of not rendering the entire treeview disabled -- so you can still select/expand/collapse rows, click column headings to sort, etc -- you just won't be able to resize the columns.

Note that even though resizing is disabled, the "double arrow" cursor (⇔) will still appear. You could additionally prevent the double arrow cursor from showing by doing the exact same thing with the <Motion> event (binding to it, checking if it's above a separator, and stopping the event from being propagated by returning the string "break").

>>> sys.version
'3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)]'
>>> tkinter.TkVersion
8.6
Danell answered 8/9, 2017 at 16:2 Comment(4)
Thank you, this fully answers my question. I'm no longer using tkinter, but this should help future readers.Laryngotomy
One of the recent Tk-8.5.x updates must've added "identify_region", as it is available in current Python-2.7.14.Gelasius
You can nest if tree.identify_column(event.x) == '#1' to further specify an exact column to have that specific column's width fixed.Zoniazoning
Using the <Motion> event works, so long as the user does not click. The moment user clicks, the event changes and the double arrow cursor shows.Ratite
T
3

I'll throw my hat in the ring - here's a dead-simple solution I found that prevents the user from resizing all columns in a ttk Treeview (named 'my_treeview' in this example):

my_treeview.bind('<Motion>', 'break')

HOW?

By binding a handler to the '<Motion>' event and setting it to 'break', hovering over column separators with the mouse no longer brings up the resize cursor (all mouse motion events are effectively disabled).

Treeview elements are still clickable and scrollable as usual, and setting column widths still works as expected.

Tinned answered 1/4, 2022 at 16:56 Comment(0)
C
2

I just found a decent solution. You can capture the mouse click before it reaches the widget, preventing the user to modify the column width.

def disableEvent(event):
    return "break"

treeviewName.bind("<Button-1>", disableEvent)

In case you need to really check which widget was pressed the event.widget contains the widget that was pressed.

Capablanca answered 20/8, 2017 at 22:12 Comment(2)
Hey, I like the idea, but wouldn't that disable clicks on Treeview items? I can't test it because I eventually moved on to GTK 3. Have you tested it?Laryngotomy
I used it to disable the whole widget. Maybe one could use identify_row and/or identify_column to allow clicks on the treeview rows but block all other clicks.Capablanca
S
0

you can horizontally scroll treeview, when i rezize the colomns(at runtime, drag to the right 'off screen') the xscrollbar gets activated, resize the column (bigger) in you code using an event after creation of scrollbar and treeview, such as push of button(say when treeview gets filled), else '.xview' detects nothing

vsbx = tkinter.Scrollbar(root_search_stock, orient="horizontal")
vsbx.place(x= 40, y = 550, width = 1000)


tree = tkinter.ttk.Treeview(root_search_stock,\
                           columns=column_names,yscrollcommand=vsby.set,xscrollcommand=vsbx.set)
tree.place(x = 50, y = 300)


vsbx.config(command = tree.xview)
Scheffler answered 22/2, 2018 at 14:30 Comment(0)
S
0

Combining the answers from the other people:

def prevent_resize(event):
    if treeview.identify_region(event.x, event.y) == "separator":
        return "break"
treeview.bind('<Button-1>', prevent_resize)
treeview.bind('<Motion>', prevent_resize)

This blocks the resize, and also hides the "resize" mouse pointer

Surah answered 6/6, 2022 at 15:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.