我正在使用ttk Treeview小部件来实现文件夹/路径选择对话框。除了我的水平滚动条不会激活外,它都按预期工作。无论文件夹路径横向有多宽,无论窗口有多窄,都不会出现水平滑块。垂直滚动工作正常。
当你在树视图中只使用一列时,或者只是在配置和连接小部件时出现新手错误时,我认为它要么是某种限制。我打赌后者。
扩展对话框以显示完整文件夹深度的示例:
对话框缩小到水平滚动应该激活的程度(但不是):
这是我的GUI布局代码:
winDirSel = tk.Toplevel()
winDirSel.title('Select Test Directory...')
tvwDirSel = ttk.Treeview(winDirSel,
height=10,padding=3,
show='tree')
lblTestDir = tk.Label(winDirSel, relief=tk.SUNKEN,
justify=tk.LEFT, anchor=tk.W,
textvariable=ctrlTestDir,width=80)
scbHDirSel = ttk.Scrollbar(winDirSel,
orient=tk.HORIZONTAL,
command=tvwDirSel.xview)
scbVDirSel = ttk.Scrollbar(winDirSel,
orient=tk.VERTICAL,
command=tvwDirSel.yview)
tvwDirSel.configure(xscrollcommand=scbHDirSel.set,
yscrollcommand=scbVDirSel.set)
lblTestDir.grid(row=0,column=0,sticky=tk.EW)
tvwDirSel.grid(row=1,column=0,sticky=tk.NSEW)
scbVDirSel.grid(row=1,column=1,sticky=tk.NS)
scbHDirSel.grid(row=2,column=0,sticky=tk.EW)
winDirSel.rowconfigure(1,weight=1)
winDirSel.columnconfigure(0,weight=1)
答案 0 :(得分:10)
好的,在玩了minwidth
和stretch
之后,我想我有更好的处理方法。水平滚动是由列边缘从窗口边界出来而不是列的内容触发的。因此,您可以使用这些参数来强制列更宽,从而强制滚动。
但问题是你失去了自动调整列宽以适应树本身的宽度。您要么必须强制它以适应任何(假定的)可能的文件夹深度,要么您在文件夹名称被截断在列的右边界处。
所以底线:它只是小部件本身的限制。 (至少关于它在我的平台上的行为,MS Windows。)
答案 1 :(得分:3)
这是我最终想出来的TreeView
文件,这些文件是PanedWindow
内部的Notebook
懒惰加载的文件(感谢this answer)(SplitterWindow in wxPython术语)和import os
import Tkinter as tk
import ttk as ttk
from ScrolledText import ScrolledText
class App(object):
def __init__(self, master, path):
splitter = tk.PanedWindow(master, orient=tk.HORIZONTAL)
# left-side
frame_left = tk.Frame(splitter)
self.tree = ttk.Treeview(frame_left, show='tree')
ysb = ttk.Scrollbar(frame_left, orient='vertical', command=self.tree.yview)
xsb = ttk.Scrollbar(frame_left, orient='horizontal', command=self.tree.xview)
# right-side
frame_right = tk.Frame(splitter)
nb = ttk.Notebook(frame_right)
page1 = ttk.Frame(nb)
page2 = ttk.Frame(nb)
text = ScrolledText(page2)
# overall layout
splitter.add(frame_left)
splitter.add(frame_right)
splitter.pack(fill=tk.BOTH, expand=1)
# left-side widget layout
self.tree.grid(row=0, column=0, sticky='NSEW')
ysb.grid(row=0, column=1, sticky='ns')
xsb.grid(row=1, column=0, sticky='ew')
# left-side frame's grid config
frame_left.columnconfigure(0, weight=1)
frame_left.rowconfigure(0, weight=1)
# right-side widget layout
text.pack(expand=1, fill="both")
nb.add(page1, text='One')
nb.add(page2, text='Two')
nb.pack(expand=1, fill="both")
# setup
self.tree.configure(yscrollcommand=lambda f, l:self.autoscroll(ysb,f,l), xscrollcommand=lambda f, l:self.autoscroll(xsb,f,l))
# use this line instead of the previous, if you want the scroll bars to always be present, but grey-out when uneeded instead of disappearing
#self.tree.configure(yscrollcommand=ysb.set, xscrollcommand=xsb.set)
self.tree.heading('#0', text='Project tree', anchor='w')
self.tree.column("#0",minwidth=1080, stretch=True)
# add default tree node
abspath = os.path.abspath(path)
self.nodes = dict()
self.insert_node('', abspath, abspath)
self.tree.bind('<<TreeviewOpen>>', self.open_node)
def autoscroll(self, sbar, first, last):
"""Hide and show scrollbar as needed."""
first, last = float(first), float(last)
if first <= 0 and last >= 1:
sbar.grid_remove()
else:
sbar.grid()
sbar.set(first, last)
def insert_node(self, parent, text, abspath):
node = self.tree.insert(parent, 'end', text=text, open=False)
if os.path.isdir(abspath):
self.nodes[node] = abspath
self.tree.insert(node, 'end')
def open_node(self, event):
node = self.tree.focus()
abspath = self.nodes.pop(node, None)
if abspath:
self.tree.delete(self.tree.get_children(node))
for p in os.listdir(abspath):
self.insert_node(node, p, os.path.join(abspath, p))
if __name__ == '__main__':
root = tk.Tk()
root.geometry("800x600")
app = App(root, path='.')
root.mainloop()
。由于this example,滚动条会根据需要自动显示/隐藏。
{{1}}
答案 2 :(得分:1)
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.font as tk_font
class TreeListBox:
def __init__(self, master, root, dict_group):
self.master = master
self.root = root
self.dict_group = dict_group
self.level = 0
self.setup_widget_tree()
self.build_tree(self.root, '')
def setup_widget_tree(self):
container_tree = tk.Frame(self.master, width=250, height=300)
container_tree.propagate(False)
container_tree.pack(side="left", fill='y')
self.tree = ttk.Treeview(container_tree, show="tree", selectmode='browse')
fr_y = tk.Frame(container_tree)
fr_y.pack(side='right', fill='y')
tk.Label(fr_y, borderwidth=1, relief='raised', font="Arial 8").pack(side='bottom', fill='x')
sb_y = tk.Scrollbar(fr_y, orient="vertical", command=self.tree.yview)
sb_y.pack(expand='yes', fill='y')
fr_x = tk.Frame(container_tree)
fr_x.pack(side='bottom', fill='x')
sb_x = tk.Scrollbar(fr_x, orient="horizontal", command=self.tree.xview)
sb_x.pack(expand='yes', fill='x')
self.tree.configure(yscrollcommand=sb_y.set, xscrollcommand=sb_x.set)
self.tree.pack(fill='both', expand='yes')
def build_tree(self, parent, id_stroki):
self.level += 1
id = self.tree.insert(id_stroki, 'end', text=parent)
# -----------------
col_w = tk_font.Font().measure(parent)
if col_w > 1000:
col_w -= 400
elif col_w > 500:
col_w -= 200
elif col_w > 300:
col_w -= 100
col_w = col_w + 25 * self.level
if col_w > self.tree.column('#0', 'width'):
self.tree.column('#0', width=col_w)
# -----------------
for element in sorted(self.dict_group[parent]):
self.build_tree(element, id)
self.level -= 1
if __name__ == '__main__':
dict_group = {'Nomenclature': ['ABC1', 'ABC2'],
'ABC1': ['ABC3', 'ABC4'],
'ABC2': ['ABC5'],
'ABC3': ['ABC______________________________________6'],
'ABC4': ['ABC--------------------------------------8'],
'ABC5': ['ABC######################################9'],
'ABC______________________________________6': [],
'ABC--------------------------------------8': [],
'ABC######################################9': []
}
root = tk.Tk()
myTest = TreeListBox(root, 'Nomenclature', dict_group)
root.mainloop()