如果按按钮命令插入,Treeview 列最初不会拉伸,但会在手动函数调用时拉伸

问题描述 投票:0回答:2

我在框架中有一个树视图。该树由网格几何管理器管理。 按下按钮我想:

  1. 改变树的列跨度
  2. 改变树的数据(包括它的列数)

树应该粘在网格的两端,柱子应该延伸到树的两侧。 我试图通过使用新的 columnspan 重新映射树、删除树的子项并添加新列来实现这一点。参见 toggle_span()。

import tkinter as tk
from tkinter import ttk

def setup_tree():
    columns = ["col1"]
    tree['columns'] = columns

    tree.column('#0', width=20, minwidth=20, stretch=tk.YES)
    tree.heading('#0', text='id')
    for i, column in enumerate(columns):
        tree.column(i, width=20, minwidth=20, stretch=tk.YES)
        tree.heading(i, text=column)

    tree.insert('', 'end', iid='1', text='1', values=("item1",))
    tree.insert('', 'end', iid='2', text='2', values=("item2",))

# Toggle treeview
def toggle_span():
    global span

    # Extend tree
    if span == 1:
        span = 2
        columns = ["col1", "col2"]
        row1 = ("item1", "item2")
        row2 = ("item3", "item4")

    # Retract tree
    else:
        span = 1
        columns = ["col1"]
        row1 = ("item1",)
        row2 = ("item2",)

    # Refresh columnspan of old tree
    tree.grid_forget()
    tree.grid(column=1, row=0, sticky="nsew", columnspan=span)

    # Clear tree
    for item in tree.get_children():
        tree.delete(item)

    # Rebuild tree
    tree['columns'] = columns

    tree.column('#0', width=20, minwidth=20, stretch=tk.YES)
    tree.heading('#0', text='id')
    for i, column in enumerate(columns):
        tree.column(i, width=20, minwidth=20, stretch=tk.YES)
        tree.heading(i, text=column)

    tree.insert('', 'end', iid='1', text='1', values=row1)
    tree.insert('', 'end', iid='2', text='2', values=row2)

span = 1

# Root
root = tk.Tk()
root.state("zoomed")

# Frame
frame = tk.Frame(root, bg="cyan")
frame.pack(fill='both', expand=True)

frame.grid_rowconfigure(0, weight=1)
for i in range(3):
    frame.grid_columnconfigure(i, weight=1) 

# Button
button = tk.Button(frame, text="Toggle Span", command=toggle_span)
button.grid(column=0, row=0, sticky="nsew")

# Tree
tree = ttk.Treeview(frame)
setup_tree()
tree.grid(column=1, row=0, sticky="nsew", columnspan=span)

# Manual toggle works as expected!
toggle_span()
toggle_span()

root.mainloop()

当手动调用 toggle_span() 时,列会按预期拉伸。然而,当通过按下按钮调用 toggle_span() 时,只有初始缩回状态和紧随其后的扩展状态才能正确显示。之后,列最初不会拉伸。但是,当单击列的边缘时,它们确实会拉伸。 Column states

如何确保列始终处于拉伸状态?

python tkinter button treeview
2个回答
0
投票

具体解决方案:

在修改第一个树视图列后调用 grid_forget(但在其余列之前)。

...

tree.column('#0', width=20, minwidth=20, stretch=tk.YES)
tree.heading('#0', text='id')

tree.grid_forget()
tree.grid(column=1, row=0, sticky="nsew", columnspan=span)  

for i, column in enumerate(columns):
    tree.column(i, width=20, minwidth=20, stretch=tk.YES)
    tree.heading(i, text=column)

...

在此之后,列将按预期伸展。我不知道为什么会这样。

这几列几乎不可见,但是按钮和树视图的宽度并不总是相同的,它们有点晃动。这可以通过将框架列配置为 uniform.

来解决
frame.grid_rowconfigure(0, weight=1)
for i in range(3):
    frame.grid_columnconfigure(i, weight=1, uniform="colgroup") 

更通用的解决方案:

为树视图创建一个独特的框架以适应。可以通过调整此框架的大小来调整树的大小。有了这个,列按预期伸展。

内部框架的 columnspan 可以直接使用 grid_configure(columnspan=...) 代替 grid_forget()grid().

然而,现在内部框架根据树视图变化,导致更狂野的“摇摆”。为了阻止这种情况,我们可以在内部框架上调用 grid_propagate(False)

问题示例代码:

import tkinter as tk
from tkinter import ttk

def setup_tree():
    columns = ["col1"]
    tree['columns'] = columns

    tree.column('#0', width=20, minwidth=20, stretch=tk.YES)
    tree.heading('#0', text='id')
    for i, column in enumerate(columns):
        tree.column(i, width=20, minwidth=20, stretch=tk.YES)
        tree.heading(i, text=column)

    tree.insert('', 'end', iid='1', text='1', values=("item1",))
    tree.insert('', 'end', iid='2', text='2', values=("item2",))

# Toggle treeview
def toggle_span():
    global span

    # Extend tree
    if span == 1:
        span = 2
        columns = ["col1", "col2"]
        row1 = ("item1", "item2")
        row2 = ("item3", "item4")

    # Retract tree
    else:
        span = 1
        columns = ["col1"]
        row1 = ("item1",)
        row2 = ("item2",)
    
    # Clear tree
    for item in tree.get_children():
        tree.delete(item)

    # Rebuild tree
    tree['columns'] = columns

    tree.column('#0', width=20, minwidth=20, stretch=tk.YES)
    tree.heading('#0', text='id')
    for i, column in enumerate(columns):
        tree.column(i, width=20, minwidth=20, stretch=tk.YES)
        tree.heading(i, text=column)

    tree.insert('', 'end', iid='1', text='1', values=row1)
    tree.insert('', 'end', iid='2', text='2', values=row2)

    tree_frame.grid_configure(columnspan=span)

span = 1

# Root
root = tk.Tk()
root.state("zoomed")

# Frame
frame = tk.Frame(root, bg="cyan")
frame.pack(fill='both', expand=True)

frame.grid_rowconfigure(0, weight=1)
for i in range(3):
    frame.grid_columnconfigure(i, weight=1) 

# Tree frame
tree_frame = tk.Frame(frame)
tree_frame.grid(row=0, column=1, sticky="nsew", columnspan=span)
tree_frame.grid_propagate(False)

tree_frame.grid_rowconfigure(0, weight=1)
tree_frame.grid_columnconfigure(0, weight=1)

# Button
button = tk.Button(frame, text="Toggle Span", command=toggle_span)
button.grid(column=0, row=0, sticky="nsew")

# Tree
tree = ttk.Treeview(tree_frame)
setup_tree()
tree.grid(row=0, column=0, sticky="nsew")

root.mainloop()

关于“手动”函数调用:

我不太明白发生了什么,但这是我所看到的。

列很好地伸展,因为树视图在主循环之前切换。 它们在主循环期间仍然会收缩,即使没有通过按下按钮调用切换:

# Produces unexpected state
def toggle():
    print("toggling")
    toggle_span()
    root.after(2000, toggle)
root.after(2000, toggle)

root.mainloop()

-1
投票

这似乎是 Tcl/Tk 的一个错误,因为

Treeview
小部件不会根据当前小部件宽度调整列的大小。

您可以通过在重新创建列后调用

grid_forget()
grid()
来解决这个问题,如下例所示。

...
def toggle_span():
    ...
    # Clear tree
    for item in tree.get_children():
        tree.delete(item)

    # Rebuild tree
    tree['columns'] = columns

    ...
    tree.grid_forget()
    tree.grid(column=1, row=0, sticky="nsew", columnspan=span)

...
© www.soinside.com 2019 - 2024. All rights reserved.