Reputation: 1247
I have a treeview widget that you can zoom in and out the font size. The problem is the indentation is not proportional when zoomed in as to when it's normal. Is there a way to adjust the indentation width? Below are two images one is normal the other is zoomed. I also wonder if there is a way to change the indicator image?
UPDATE: I have solved the indentation problem thanks to jasonharper comments below. I still need to change the indicator arrow image can't seem to find any info on the web.
Upvotes: 3
Views: 2147
Reputation: 1947
I took the accepted answer and tweaked the code. It is a bit shorter and more robust by calculating polygon coordinates automatically using the treeview row height as a parameter.
''' Create images for open, close and empty '''
width = row_height-7
im_open, im_close, im_empty = triangle_raw_images(width,
'black', 'LightGrey')
img_open = ImageTk.PhotoImage(im_open)
img_close = ImageTk.PhotoImage(im_close)
img_empty = ImageTk.PhotoImage(im_empty)
# custom indicator
style.element_create('Treeitem.myindicator', 'image', img_close,
('user1', '!user2', img_open), ('user2', img_empty),
sticky='w', width=width)
# replace Treeitem.indicator by custom one
style.layout('Treeview.Item',
[('Treeitem.padding',
{'sticky': 'nswe',
'children': [
('Treeitem.myindicator', {'side': 'left', 'sticky': ''}),
('Treeitem.image', {'side': 'left', 'sticky': ''}),
('Treeitem.focus', {'side': 'left', 'sticky': '','children':
[('Treeitem.text',
{'side': 'left','sticky': ''})]
})
]
})])
Changes above from Accepted Answer:
row_height
is same variable passed to treeview which is needed for HiDPI screens when larger font size is used.ImageTk.PhotoImage(im_open)
is used instead of ImageTk.PhotoImage(im_open, name='img_open', master=root)
The heart of the change is a new function:
def triangle_raw_images(hgt, outc, fillc):
from PIL import Image, ImageTk, ImageDraw # Pillow image processing
# For comments in code assume passed hgt = 21
wid = hgt # square image
hgt_off = 4 # top & bottom whitespace
wxy = ( 0, hgt_off, ) # west point x=0, y=4
exy = ( wid-1, hgt_off, ) # east point x=20, y=4
sxy = ( int((hgt-1)/2), hgt-hgt_off, ) # south point x=10, y=17
retn_images = [] # list of three images
# custom indicator images
im_open = Image.new('RGBA', (wid, hgt), (0, 0, 0, 0))
im_empty = Image.new('RGBA', (wid, hgt), (0, 0, 0, 0))
draw = ImageDraw.Draw(im_open)
draw.polygon([ wxy, exy, sxy ], outline=outc, fill=fillc)
im_close= im_open.rotate(90)
return im_open, im_close, im_empty
Here is the end result:
Upvotes: 1
Reputation: 16179
Indentation
As said in the comments by jasonharper and Daniel Huckson, the indentation can be changed with
style.configure('Treeview', indent=100)
Indicator image
The indicator image can be changed by creating a custom theme element and using it in replacement of the standard indicator in the Treeview.Item
layout.
The key point here is to know the names of the states of an opened item ('user1') and of an item without children ('user2'), closed being the default state. Therefore the open indicator needs to be mapped with items in the state ('user1', '!user2')
and the empty image to the items in state ('user2', )
.
I used PIL to create dummy images for the indicator, but one can directly load custom images instead.
from PIL import Image, ImageTk, ImageDraw
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
style = ttk.Style(root)
# custom indicator images
im_open = Image.new('RGBA', (15, 15), '#00000000')
im_empty = Image.new('RGBA', (15, 15), '#00000000')
draw = ImageDraw.Draw(im_open)
draw.polygon([(0, 4), (14, 4), (7, 11)], fill='yellow', outline='black')
im_close= im_open.rotate(90)
img_open = ImageTk.PhotoImage(im_open, name='img_open', master=root)
img_close = ImageTk.PhotoImage(im_close, name='img_close', master=root)
img_empty = ImageTk.PhotoImage(im_empty, name='img_empty', master=root)
# custom indicator
style.element_create('Treeitem.myindicator',
'image', 'img_close', ('user1', '!user2', 'img_open'), ('user2', 'img_empty'),
sticky='w', width=15)
# replace Treeitem.indicator by custom one
style.layout('Treeview.Item',
[('Treeitem.padding',
{'sticky': 'nswe',
'children': [('Treeitem.myindicator', {'side': 'left', 'sticky': ''}),
('Treeitem.image', {'side': 'left', 'sticky': ''}),
('Treeitem.focus',
{'side': 'left',
'sticky': '',
'children': [('Treeitem.text', {'side': 'left', 'sticky': ''})]})]})]
)
tree = ttk.Treeview(root)
tree.pack()
tree.insert('', 'end', text='item 1', open=True)
tree.insert('', 'end', text='item 2')
tree.insert('I001', 'end', text='item 11', open=False)
tree.insert('I001', 'end', text='item 12', open=False)
tree.insert('I004', 'end', text='item 121', open=False)
root.mainloop()
Upvotes: 9