【问题标题】:Dynamically add columns in Tkinter treeview在 Tkinter 树视图中动态添加列
【发布时间】:2020-10-27 20:53:49
【问题描述】:

该程序应该动态添加列,以便在按下相应按钮时显示更多数据。可以以不同的顺序按下按钮,这会影响下一列/标题的外观。正如您在示例程序中看到的那样,标头没有正确更新。表中只显示了最后一个。如果item(选中的行和列)已经有数据,应该更新,但目前数据只添加到新的列中,所以问题之一是如何更新选中的行和标题引用的item。删除行时,应删除所有空列。 我正在尝试通过连接元组来更新列,但不知道如何处理标题。 任何建议都非常感谢。

from random import randint
from tkinter import *
from tkinter.ttk import Treeview


def get_window():
    root = Tk()
    root.resizable(width=True, height=True)
    root.geometry("823x458")
    root.title("PsControl")
    return root


def get_top_frame(root):
    frame = Frame(root)
    frame.name = 'top_frame'

    frame.root = root

    frame.pack(side=TOP, expand=False, fill=X)

    button1 = Button(frame, text="Add Row", command=lambda: tv.insert('', 'end', text="hostname"))
    button1.grid(row=0, column=1)

    button1 = Button(frame, text="Add Cow 1", command=lambda: tv_insert("H1", randint(1, 100)))
    button1.grid(row=0, column=2)

    button2 = Button(frame, text="Add Cow 2", command=lambda: tv_insert("H2", randint(1, 100)))
    button2.grid(row=0, column=3)

    button3 = Button(frame, text="Add Cow 3", command=lambda: tv_insert("H3", randint(1, 100)))
    button3.grid(row=0, column=4)

    button4 = Button(frame, text="Add Cow 20", command=lambda: tv_insert("H4", randint(1, 100)))
    button4.grid(row=0, column=5)

    button5 = Button(frame, text="Delete row", command=lambda: tv.delete(tv.selection()))
    button5.grid(row=0, column=6)


def get_bottom_frame(root):
    global tv
    frame = Frame(root, highlightbackground='#3E4149', highlightthickness=1, borderwidth=2)
    frame.name = 'bottom_frame'
    frame.root = root

    h = Scrollbar(root, orient='horizontal')
    h.pack(side=BOTTOM, fill=X)
    v = Scrollbar(root)
    v.pack(side=RIGHT, fill=Y)

    frame.pack(side=BOTTOM, expand=True, fill=BOTH)
    frame.config(background='#FFFFFF')

    tv = Treeview(frame, xscrollcommand=h.set, yscrollcommand=v.set)

    tv.column("#0", width=135, minwidth=35, stretch=NO)
    tv.heading("#0", text='Host', anchor='w')

    tv.pack(expand=True, fill='both')

    h.config(command=tv.xview)
    v.config(command=tv.yview)


def tv_insert(heading, insert_data):
    selection = tv.selection()
    columns = tv["columns"]

    if columns == '':
        tv["columns"] = (heading,)
        tv.column(heading, width=135, minwidth=35, stretch=NO)
        tv.heading(heading, text=heading, anchor='w')
        tv.item(selection, values=insert_data)
    else:
        new_col = columns + (heading,)
        tv["columns"] = new_col

        tv.heading(heading, text=heading, anchor='w')

        data = tv.item(selection, "values")
        if data == '':
            tv.item(selection, values=insert_data)
        else:
            new_data = data + (insert_data,)
            tv.item(selection, values=new_data)


def delete_row():
    selection = tv.selection()
    tv.delete(selection)


root = get_window()
get_top_frame(root)
get_bottom_frame(root)

root.mainloop()

感谢@acw1668,这里的答案是按预期完成工作的代码。欢迎提出任何改进建议。

def tv_insert(heading, insert_data):
    selection = tv.selection()
    columns = tv["columns"]
    if columns == '':  # if no columns, create column, heading and item.
        tv["columns"] = (heading,)
        tv.column(heading, width=135, minwidth=35, stretch=NO)
        tv.heading(heading, text=heading, anchor='w')
        tv.item(selection, values=(insert_data,))
    else:
        headings = [tv.heading(col) for col in columns] # save current headings

        if heading not in columns:
            new_col = columns + (heading,)
            tv["columns"] = new_col
            # restore previous headings
            for h in headings:
                tv.heading(h['text'], text=h['text'], anchor=h['anchor'])
            # set new heading
            tv.heading(heading, text=heading, anchor='w')
            # add data/item with with size of the columns
            len_col = len(new_col)
            data = ['' for _ in range(len_col)]    # Create an empty list
            data[len_col - 1] = insert_data                # Update the next
            tv.item(selection, values=tuple(data))

        else:
            data = tv.item(selection, "values")
            # if heading exist but no item on the the selected row
            if data == '':
                data = ['' for _ in range(len(headings))]
                index = columns.index(heading)
                data[index] = insert_data
                tv.item(selection, values=tuple(data))
            else:
                data = list(data)
                if len(data) < len(columns):
                    new_data = ['' for _ in range(len(columns))]
                    for i, d in enumerate(data):
                        new_data[i] = d
                    index = columns.index(heading)
                    new_data[index] = insert_data
                    tv.item(selection, values=tuple(new_data))
                else:
                    index = columns.index(heading)
                    data[index] = insert_data
                    tv.item(selection, values=tuple(data))

【问题讨论】:

    标签: python tkinter treeview


    【解决方案1】:

    由于您已将 列分配给tv,因此标题信息将丢失。您应该在分配 new 列之前保存当前的标题信息并在之后恢复它们:

    def tv_insert(heading, insert_data):
        selection = tv.selection()
        columns = tv["columns"]
    
        if columns == '':
            tv["columns"] = (heading,)
            tv.column(heading, width=135, minwidth=35, stretch=NO)
            tv.heading(heading, text=heading, anchor='w')
            tv.item(selection, values=insert_data)
        else:
            headings = [tv.heading(col) for col in columns] # save current headings
            new_col = columns + (heading,)
            tv["columns"] = new_col
    
            # restore previous headings
            for h in headings:
                tv.heading(h['text'], text=h['text'], anchor=h['anchor'])
            # set new heading
            tv.heading(heading, text=heading, anchor='w')
    
            data = tv.item(selection, "values")
            if data == '':
                tv.item(selection, values=insert_data)
            else:
                new_data = data + (insert_data,)
                tv.item(selection, values=new_data)
    

    【讨论】:

    • 谢谢!这正是我想要的。我进行了一些更改以涵盖更多案例,并且我正在共享运行良好的代码。如果 item 为空,程序会创建一个长度为 len(columns) 的空字符串列表,然后更新元素(而不是追加)并将其保存为元组。如果该项目存在,则将其写入空字符串的 e 列表,然后更新该元素。代码可以改进,但总的来说程序会按照预期进行。
    猜你喜欢
    • 2019-02-03
    • 2018-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多