简体   繁体   English

在 Tkinter 树视图中动态添加列

[英]Dynamically add columns in Tkinter treeview

The program is supposed to add columns dynamically in order to present more data when corresponding button is pressed.该程序应该动态添加列,以便在按下相应按钮时显示更多数据。 The buttons can be pressed in different order and that effects the appearance of the next column/header.可以按不同顺序按下按钮,这会影响下一列/标题的外观。 As you can see in the example program, the headers are not updated correctly.正如您在示例程序中看到的,标题没有正确更新。 Only the last one is shown in the table.表中仅显示最后一个。 If the item (selected row and column) already has data, it should be updated, but currently the data is added only in new column, so one of the questions is how to update an item referred by selected row and header.如果项目(选中的行和列)已经有数据,应该更新,但目前数据只添加到新列中,所以问题之一是如何更新选中的行和标题引用的项目。 When the row is deleted, all empty columns should be removed.删除行后,应删除所有空列。 I'm trying to update the columns by concatenating tuples, but have no idea how to deal with the headers.我试图通过连接元组来更新列,但不知道如何处理标题。 Any suggestions are very appreciated.任何建议都非常感谢。

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()

Thanks to @acw1668 answer here is the code that does the job as expected.感谢@acw1668,这里是按预期完成工作的代码。 Any suggestions for improvement are welcome.欢迎提出任何改进建议。

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))

Since you have assigned new columns to tv , the headings information is lost.由于您已将列分配给tv ,因此标题信息将丢失。 You should save the current headings information before assigning the new columns and restore them after:您应该在分配列之前保存当前标题信息,并在以下时间恢复它们:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM