【问题标题】:Treeview frame on canvas画布上的树视图框架
【发布时间】:2019-05-21 14:59:58
【问题描述】:

这段代码有2个问题:
1. 我无法让树视图框架填充整个画布(垂直)
2. 我不想显示第一列
我该如何解决这些问题?

import os

import time
import datetime
from datetime import timedelta
from tkinter.constants import TRUE

try:
    import Tkinter as tk
    import tkFont
    import ttk

    from Tkconstants import CENTER, LEFT, N, E, W, S
    from Tkinter import StringVar
except ImportError: # py3k
    import tkinter as Tkinter
    import tkinter.font as tkFont
    import tkinter.ttk as ttk

    from tkinter.constants import CENTER, LEFT, N, E, W, S
    from tkinter import StringVar

GRID_BORDER_WIDTH = "1"

def populate_treeview(frame, my_column_headers, my_list):

    style = ttk.Style()
    style.configure("mystyle.Treeview", highlightthickness=0, bd=0, font=('Calibri', 11)) # Modify the font of the body
    style.configure("mystyle.Treeview.Heading", font=('Calibri', 13,'bold')) # Modify the font of the headings
    style.layout("mystyle.Treeview", [('mystyle.Treeview.treearea', {'sticky': 'nswe'})]) # Remove the borders

    tree=ttk.Treeview(frame, style="mystyle.Treeview") # create the widget

    tree["columns"]=my_column_headers
    for i in range (0,26):
        tree.column(my_column_headers[i], width=50, minwidth=20, stretch=Tkinter.YES)

    for i in range (0,26):
        tree.heading(my_column_headers[i] ,text=my_column_headers[i], anchor=Tkinter.W)

    PARENT="" # top level
    i = 0
    for item in my_list:
        #print ("item: " + str(item)) 
        tree.insert(PARENT, i, i, text=str(i), values=(item))
        i += 1

    tree.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=TRUE)

def OnFrameConfigure(canvas):
    '''Reset the scroll region to encompass the inner frame'''
    canvas.configure(scrollregion=canvas.bbox("all"))

def OnCanvasConfigure(self, event):
    width = 0
    for child in self.sensorsStatsFrame.grid_slaves():
        width += child.winfo_reqwidth()

    self.canvas.itemconfigure(self.canvas_frame, width=width, height=event.height)

# main ########################################################################
def main():

    print ("[DEBUG]***  Display Test***)\n");

    # Data
    item_column_headers =  ["a", "b", "c", "d","e", "f", "g", "h","i", "j", "k", "l","m", "n", "o", "p","q", "r", "s", "t", "u","v", "w", "x", "y", "z"]
    item_list = []
    for row_number in range (0,50):
        row = []
        for alpha in item_column_headers:
            row.append (str(row_number) + alpha)
        item_list.append(row)

    print (item_list)

    ## GUI ------------------------------------------------------------------------------

    root = Tkinter.Tk()

    canvas = Tkinter.Canvas(root, borderwidth=6, background="#222222" )

    frame = Tkinter.Frame(canvas, background="#ff0000", borderwidth = 5)
    frame.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.BOTH)
    canvas.create_window((0,0), window = frame, anchor="nw", tags="my_tag")
    canvas.bind("<Configure>", lambda event,  root=root:OnCanvasConfigure(root))

    verticalScrollbar = Tkinter.Scrollbar(root, orient="vertical", command=canvas.yview)
    canvas.configure(yscrollcommand=verticalScrollbar.set)
    verticalScrollbar.pack(side="right", fill="y", expand=0)

    horizontalScrollbar = Tkinter.Scrollbar(root, orient="horizontal", command=canvas.xview)
    canvas.configure(xscrollcommand=horizontalScrollbar.set)
    horizontalScrollbar.pack(side="bottom", fill="x", expand=0)

    canvas.pack(fill="both", expand=1)

    frame.bind("<Configure>", lambda event, canvas=canvas: OnFrameConfigure(canvas))
    #frame.bind("<Configure>", OnFrameConfigure)

    populate_treeview(frame, item_column_headers, item_list) 

    root.geometry("1000x600")
    root.wm_title("Display Test")

    root.mainloop()

    print ("\n*** Done " + str(datetime.datetime.now()) + "  - Display Test ***");

# main ###############################################################################

if __name__ == "__main__":
    # stuff only to run when not called via 'import' here
    main()

这是@BryanOakley 建议的修复代码

import os

import time
import datetime
from datetime import timedelta
from tkinter.constants import TRUE

try:
    import Tkinter as tk
    import tkFont
    import ttk

    from Tkconstants import CENTER, LEFT, N, E, W, S
    from Tkinter import StringVar
except ImportError: # py3k
    import tkinter as Tkinter
    import tkinter.font as tkFont
    import tkinter.ttk as ttk

    from tkinter.constants import CENTER, LEFT, N, E, W, S
    from tkinter import StringVar

GRID_BORDER_WIDTH = "1"

def populate_treeview(frame, my_column_headers, my_list):

    style = ttk.Style()
    style.configure("mystyle.Treeview", highlightthickness=0, bd=0, font=('Calibri', 11)) # Modify the font of the body
    style.configure("mystyle.Treeview.Heading", font=('Calibri', 13,'bold')) # Modify the font of the headings
    style.layout("mystyle.Treeview", [('mystyle.Treeview.treearea', {'sticky': 'nswe'})]) # Remove the borders

    tree=ttk.Treeview(frame, style="mystyle.Treeview") # create the widget

    vsb = ttk.Scrollbar(tree, orient="vertical", command=tree.yview)
    vsb.configure(command=tree.yview)
    vsb.pack(side='right', fill='y')
    tree.configure(yscrollcommand=vsb.set)

    hsb = ttk.Scrollbar(tree, orient="horizontal", command=tree.xview)
    hsb.configure(command=tree.xview)
    hsb.pack(side='bottom', fill='x')
    tree.configure(xscrollcommand=hsb.set)

    tree["columns"]=my_column_headers

    for i in range (0,26):
        tree.column(my_column_headers[i], width=50, minwidth=20, stretch=Tkinter.YES)

    for i in range (0,26):
        tree.heading(my_column_headers[i] ,text=my_column_headers[i], anchor=Tkinter.W)

    PARENT="" # top level
    i = 0
    for item in my_list:
        #print ("item: " + str(item)) 
        tree.insert(PARENT, i, i, text=str(i), values=(item))
        i += 1

    tree["show"] = ["headings"]        
    tree.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=TRUE)

# main ########################################################################
def main():

    print ("[DEBUG]***  Display Test***)\n");

    # Data
    item_column_headers =  ["a", "b", "c", "d","e", "f", "g", "h","i", "j", "k", "l","m", "n", "o", "p","q", "r", "s", "t", "u","v", "w", "x", "y", "z"]
    item_list = []
    for row_number in range (0,50):
        row = []
        for alpha in item_column_headers:
            row.append (str(row_number) + alpha)
        item_list.append(row)

    ## GUI ------------------------------------------------------------------------------

    root = Tkinter.Tk()

    frame = Tkinter.Frame(root, background="#ff0000", borderwidth = 5)
    frame.pack(side=Tkinter.TOP, expand=1, fill=Tkinter.BOTH)

    populate_treeview(frame, item_column_headers, item_list) 

    root.geometry("1000x600")
    root.wm_title("Display Test")

    root.mainloop()

    print ("\n*** Done " + str(datetime.datetime.now()) + "  - Display Test ***");

# main ###############################################################################

if __name__ == "__main__":
    # stuff only to run when not called via 'import' here
    main()

【问题讨论】:

  • 尝试创建Minimal, Complete, and Verifiable example 代码来显示您遇到的问题。让问题更容易理解。
  • 这是一个独立于我正在编写的实际应用程序的测试程序。虽然它可能不是最小的,因为我不确定问题出在哪里,但它是完整且可验证的。只需将其复制/粘贴到文件中即可执行它,从而看到问题。
  • 您是否知道您发布的代码中存在此错误? TypeError: OnCanvasConfigure() missing 1 required positional argument: 'event'
  • 感谢您的回复。是的,我意识到了这一点。我已经尝试了很多东西。该错误只是我尝试的最后一件事。而且我不知道如何解决它。
  • 你为什么在某些地方使用self?这些代码都没有被定义为类的一部分。这使得代码非常混乱且难以理解。我认为您发布的代码太损坏了,我们无法解决您提出的问题。

标签: python-3.x tkinter treeview tkinter-canvas


【解决方案1】:

我无法让树视图框架填充整个画布(垂直)

树没有填满画布的问题是因为它在一个框架中,而框架没有填满画布。看起来您正试图在您的 OnCanvasConfigure 方法中解决这个问题,但有许多错误阻止它工作。

首先,你有一个循环遍历self.sensorsStatsFrame.grid_slaves(),但是你还没有定义self,并且没有名为sensorsStatsFrame的小部件,所以这个函数在它有机会改变高度之前就会失败框架。因为这段代码会抛出错误,所以函数中的后续代码都不会运行。

接下来,您尝试调用self.canvas.configure,但又没有self 和self.canvas,因此该语句将失败。您也使用self.canvas_frame,但同样,它不存在,因此代码将失败。

如果您解决了所有这些问题,代码应该允许将框架配置为与画布相同的宽度和高度,从而解决您提出的第一个问题。

我不想显示第一列

treeview 属性 show 允许您定义要显示的树的哪些部分。您为其分配一个包含"tree" 和/或"headings" 的列表。您不想看到由"tree" 表示的第一列。因此,要隐藏该值,您希望将"headings" 作为show 属性所用列表中的唯一值传递。

tree["show"] = ["headings"]

【讨论】:

  • 谢谢。 “show”很容易解决第一列的问题。我会处理另一个...
  • 删除画布并使用树视图滚动是解决方案。我已在原始问题中添加了固定代码。也许添加您对树视图滚动的评论,这是一个完整的答案。
  • @AllLelopath 我认为你所做的只是增加了混乱。该答案解决了所提出的问题。您没有询问滚动树视图,而是询问了如何使树视图与画布大小相同。这是两个完全不同的问题。
  • 我同意问题是如何将treeview 框架扩展到canvas。这个问题是在无知中问出来的。所以我可以 1. 按原样接受您的回答。 2. 删除问题。我更喜欢 1,所以除非你反对,否则我会这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-10
  • 1970-01-01
相关资源
最近更新 更多