我有一个包含树视图和按钮的框架。按下按钮时,树视图的行将被删除,列将被重新创建,标题将被命名。列设置为拉伸,树本身设置为展开。
我的理解是,此配置应该导致列拉伸以匹配包含的框架。
首次启动时,列的大小会调整,框架会与树视图的预期大小相匹配。然后我按下按钮重新分配列并调整列大小(与初始化中调用相同的函数)。
列的大小会调整,但树视图保持相同的整体宽度。如果我拖动窗口的右边缘,树视图会随着框架缩小。当框架“接触”最右边的列时,它似乎重新获得了“弹性”,并且当我调整窗口大小时,列会增大/缩小。
此外,有时(每几次启动),列的宽度设置不会在“第一次”单击按钮时发生;我在后续点击中从未见过此问题。 我搜索了几个类似的帖子,但他们指出扩展是错误的,但我在
self.tree.pack()
中将其设置为 true,以及
listbox.pack()
中的包含框架。我尝试不扩展并填写两个 pack() 语句;行为是相同的。当我调整树视图包含的列的大小时,为什么树视图没有调整大小?什么可能导致第一次单击无法调整列大小?
import tkinter as tk
import tkinter.font as tkFont
import tkinter.ttk as ttk
import random
# import natsort as ns
class MultiColumnListbox(tk.Frame):
"""Creates a multi-column "listbox" with sorting columns from a treeview class"""
def __init__(self, master=None, *args, **kwargs):
tk.Frame.__init__(self, master=master,*args, **kwargs)
# add a button to change columns
tk.Button(self, text="change columns", command=self._populate_dummy).pack(anchor=tk.NW, pady=5)
self.tree = ttk.Treeview(master=self, show="headings") # don't show tree column
self.tree.pack(fill=tk.X, expand=True) # place tree in the parent frame
# initialize to random values
self._populate_dummy()
def _populate_dummy(self):
# generate column names
colnames = ["item number"]
numcols = random.randint(1,6)
colnames += ['col{}'.format(i) for i in range(numcols)]
self.set_headers(colnames)
# generate row contents
rows = []
for i in range(20):
vals = ['item{}'.format(i)]
for _ in range(numcols):
vals += [random.randint(1,100)]
rows.append(tuple(vals))
self.set_rows(rows)
# set the table headers
def set_headers(self, columns):
self.tree.configure(columns=columns)
for i, col in enumerate(columns):
column_width = tkFont.Font().measure(col.title())
self.tree.heading(i, text=col)
self.tree.column(i, width=column_width, stretch=True) # add column, set width to match header
# set the row values
def set_rows(self, rows):
# clear rows
for child in self.tree.get_children():
self.tree.delete(child)
# apply new rows
for i, item in enumerate(rows):
tags = [(), ('oddrow',)]
self.tree.insert('', 'end', values=item, tags=tags[i%2])
self.tree.tag_configure('oddrow', background='gray80')
if __name__ == '__main__':
root = tk.Tk()
root.title("Multicolumn Treeview/Listbox")
listbox = MultiColumnListbox(root)
listbox.pack(padx=10, pady=10, fill=tk.X, expand=True)
root.mainloop()
此图显示了程序在红色描述的条件下的状态。更新
我已经用调用来包装
set_headers()
来获取树视图及其包含框架(自身)的宽度,所以 _populate_dummy() 现在是:
def _populate_dummy(self):
# generate column names
colnames = ["item number"]
numcols = random.randint(1,6)
colnames += ['col{}'.format(i) for i in range(numcols)] + []
print("BEFORE")
print("frame width: {}".format(frame_width))
tree_width = self.tree.winfo_width()
print("table width: {}".format(tree_width))
self.set_headers(colnames)
print("AFTER")
frame_width = self.winfo_width()
print("frame width: {}".format(frame_width))
tree_width = self.tree.winfo_width()
print("table width: {}".format(tree_width))
有趣的是,当程序在构造函数中调用 _populate_dummy() 时,会返回
BEFORE
frame width: 1
table width: 1
AFTER
frame width: 1
table width: 1
尽管视觉外观相当大。 但此后为(非 1)值。当我得到“未调整大小”版本(图中的步骤 2)时,我得到:
frame width: 99
table width: 91
frame width: 99
table width: 91
当我得到一个表格,其中列的大小正确,但框架很大时,我得到这个:
frame width: 1003
table width: 1003
frame width: 1003
table width: 1003
我应该注意到,报告的宽度似乎与列数无关,甚至不一致;我一次从 2 列中得到 1003,另一次从 2 列中得到 1203。
这似乎很重要,但我不知道如何解释它。
def _populate_dummy(self):
# generate column names
colnames = ["item number"]
numcols = random.randint(1,6)
colnames += ['col{}'.format(i) for i in range(numcols)] + ['']
self.set_headers(colnames)
然后在set_headers方法的最后一行设置空列标题宽度比当前主窗口宽度宽
def set_headers(self, columns):
self.tree.configure(columns=columns)
for i, col in enumerate(columns):
column_width = tkFont.Font().measure(col.title())
self.tree.heading(i, text=col)
self.tree.column(i, width=column_width, stretch=True) # add column, set width to match header
self.tree.column(i, width=self.winfo_width())