Обтекание текста внутри строки в древовидной структуре tkinter
Можно ли обернуть текст в строку с помощью tkinter treeview? Я пытался изменить высоту строки, но текст не переносится. в основном я хочу иметь многострочный текст в строке.
Это код:
from tkinter import*
from tkinter import ttk
myApp = Tk()
NewTree= ttk.Treeview(myApp, height=5)
NewTree['show'] = 'headings'
s = ttk.Style()
s.configure('Treeview', rowheight=40)
NewTree["columns"]=("1","2")
NewTree.column("1", width=60)
NewTree.column("2", width=60)
NewTree.heading("1", text="col a")
NewTree.heading("2", text="col b")
item = NewTree.insert("", "end", values=("i want to wrap this text","and this text"))
NewTree.grid(row=0,column=0)
myApp.mainloop()
Это вторая версия кода (когда вы можете вручную добавлять элементы в древовидную структуру). У него просто есть одна большая функция перед кодом, который я разместил выше. Я пытался поставить разные значения на lenght
но результат тот же (это не обернуть):
from tkinter import*
from tkinter import ttk
from tkinter import messagebox
import textwrap
def wrap(string, lenght=15):
return '\n'.join(textwrap.wrap(string, lenght))
myApp = Tk()
def editact(event):
def double(event): # funkcija koja kreira celiju kada se klikne dupli klik
try:
if NewTree.identify_region(event.x, event.y) == 'cell':
# the user clicked on a cell
def ok(event):
"""Change item value."""
NewTree.set(item, column, entry.get())
entry.destroy()
column = NewTree.identify_column(event.x) # identify column
item = NewTree.identify_row(event.y) # identify item
x, y, width, height = NewTree.bbox(item, column)
value = NewTree.set(item, column)
elif NewTree.identify_region(event.x, event.y) == 'heading':
# the user clicked on a heading
def ok(event):
"""Change heading text."""
NewTree.heading(column, text=entry.get())
entry.destroy()
column = NewTree.identify_column(event.x) # identify column
# tree.bbox work only with items so we have to get the bbox of the heading differently
x, y, width, _ = NewTree.bbox(NewTree.get_children('')[0], column) # get x and width (same as the one of any cell in the column)
# get vertical coordinates (y1, y2)
y2 = y
# get bottom coordinate
while NewTree.identify_region(event.x, y2) != 'heading':
y2 -= 1
# get top coordinate
y1 = y2
while NewTree.identify_region(event.x, y1) == 'heading':
y1 -= 1
height = y2 - y1
y = y1
value = NewTree.heading(column, 'text')
elif NewTree.identify_region(event.x, event.y) == 'nothing':
column = NewTree.identify_column(event.x) # identify column
# check whether we are below the last row:
x, y, width, height = NewTree.bbox(NewTree.get_children('')[-1], column)
if event.y > y:
def ok(event):
"""Change item value."""
# create item
item = NewTree.insert("", "end", values=("", ""))
NewTree.set(item, column, entry.get())
entry.destroy()
y += height
value = ""
else:
return
else:
return
# display the Entry
entry = ttk.Entry(NewTree) # create edition entry
entry.place(x=x, y=y, width=width, height=height, anchor='nw') # display entry on top of cell
entry.insert(0, value) # put former value in entry
entry.bind('<FocusOut>', ok) #validate when you click on other cell
entry.focus_set()
except IndexError:
Error=messagebox.showinfo("Error!","You have 0 rows. Please add a new row.")
sys.exit() #za resavalje greske`
pass
NewTree.bind('<Double-Button-1>', double) #create new cell with double click
NewTree= ttk.Treeview(myApp, height=5)
NewTree['show'] = 'headings'
s = ttk.Style()
s.configure('Treeview', rowheight=60)
NewTree["columns"]=("1","2")
NewTree.column("1", width=100, anchor="center")
NewTree.column("2", width=100, anchor="w")
NewTree.heading("1", text="Col A")
NewTree.heading("2", text="Col B")
item = NewTree.insert("", "end", values=(wrap(""),wrap("")))
NewTree.item(item, tags=item)
NewTree.bind('<1>', editact)
NewTree.grid(row=0,column=0, columnspan=5, padx=5)
myApp.mainloop()
2 ответа
Решение
Вы можете использовать textwrap
модуль для определения этого wrap
функция:
def wrap(string, lenght=8):
return '\n'.join(textwrap.wrap(string, lenght))
Теперь вы можете заменить item
от:
item = NewTree.insert("", "end", values=(wrap("i want to wrap this text"),
wrap("and this text")))
Полный код
from tkinter import *
from tkinter import ttk
import textwrap
def wrap(string, lenght=8):
return '\n'.join(textwrap.wrap(string, lenght))
myApp = Tk()
NewTree = ttk.Treeview(myApp, height=5)
NewTree['show'] = 'headings'
s = ttk.Style()
s.configure('Treeview', rowheight=40)
NewTree["columns"] = ("1", "2")
NewTree.column("1", width=60)
NewTree.column("2", width=60)
NewTree.heading("1", text="col a")
NewTree.heading("2", text="col b")
item = NewTree.insert("", "end", values=(wrap("i want to wrap this text"),
wrap("and this text")))
NewTree.grid(row=0, column=0)
myApp.mainloop()
Выход
Следующий код использует <B1-Motion>
событие для динамического переноса текста (поэтому поддерживается изменение размера столбцов, и текст будет соответственно "переноситься").
from tkinter import Tk, ttk
from tkinter.font import Font
from functools import partial
myApp = Tk()
NewTree= ttk.Treeview(myApp, height=5)
NewTree['show'] = 'headings'
s = ttk.Style()
s.configure('Treeview', rowheight=50)
NewTree["columns"]=("1","2")
NewTree.column("1", width=80, anchor="nw")
NewTree.column("2", width=80, anchor="nw")
NewTree.heading("1", text="col a")
NewTree.heading("2", text="col b")
item = NewTree.insert("", "end", values=("i want to wrap this text","and this text"))
print(item)
NewTree.grid(row=0,column=0)
def motion_handler(tree, event):
f = Font(font='TkDefaultFont')
# A helper function that will wrap a given value based on column width
def adjust_newlines(val, width, pad=10):
words = val.split()
lines = [[],]
for word in words:
line = lines[-1] + [word,]
if f.measure(' '.join(line)) < (width - pad):
lines[-1].append(word)
else:
lines[-1] = ' '.join(lines[-1])
lines.append([word,])
if isinstance(lines[-1], list):
lines[-1] = ' '.join(lines[-1])
return '\n'.join(lines)
if (event is None) or (tree.identify_region(event.x, event.y) == "separator"):
# You may be able to use this to only adjust the two columns that you care about
# print(tree.identify_column(event.x))
col_widths = [tree.column(cid)['width'] for cid in NewTree['columns']]
for iid in tree.get_children():
new_vals = []
for (v,w) in zip(tree.item(iid)['values'], col_widths):
new_vals.append(adjust_newlines(v, w))
tree.item(iid, values=new_vals)
NewTree.bind('<B1-Motion>', partial(motion_handler, NewTree))
motion_handler(NewTree, None) # Perform initial wrapping
myApp.mainloop()