tkinter:在每行文本旁边的文本框中动态插入按钮

时间:2018-11-06 19:28:17

标签: python python-3.x tkinter

问题:

我有一个for循环,可将文本添加到文本框中。 我希望在文本之后且每次迭代结束之前在文本框中显示一个最右侧的按钮。

是否还可以为按钮分配某种标签,即文本之前的文本? 因此,对于每次迭代,按钮都会调用一个函数并在其之前传递文本。

期望的图像:

enter image description here

2 个答案:

答案 0 :(得分:3)

您可以使用制表符将某些内容强制对齐到右边距。唯一的技巧是,每当调整窗口大小时,您都需要重新计算tabstop。您可以通过绑定到<Configure>事件来实现。当您在选项卡之后和换行符之前放置一个窗口时,它将右对齐。

您可以将lambda函数与按钮关联,以使您能够定义要发送到回调的数据。

这是一个简单的例子:

import tkinter as tk

def reset_tabs(event):
    '''Add a tabstop at the right edge of the widget'''
    right_margin = event.width - 8
    if right_margin <= 0: return
    tabs = (right_margin, "right")
    event.widget.configure(tabs=tabs)

def callback(text):
    print("you clicked {}".format(text))

root = tk.Tk()
text = tk.Text(root)
text.pack(fill="both", expand=True)
text.bind("<Configure>", reset_tabs)

for i in range(10):
    item = "this is item {}".format(i+1)
    text.insert("end", item + "\t\n")
    button = tk.Button(text, text="x", padx=2, pady=2,
                       cursor="left_ptr",
                       bd=1, highlightthickness=0,
                       command = lambda text=item: callback(text))
    text.window_create("end-2c", window=button)

root.mainloop()

上面的代码将在这样的窗口中显示:

enter image description here

答案 1 :(得分:2)

更新:

从@martineau发布的评论中,我能够构建一些可以满足您要求的东西。问题是使按钮正确对齐。我认为最好将左侧的按钮对齐,但让我知道您的想法。

import tkinter as tk

list_of_file_data = [["Data set 1!", "This is the contents of data set 1.", True],
                     ["Data set 2!", "This is the contents of data set 2.", True],
                     ["Data set 3!", "This is the contents of data set 3.", True]]

class Example(tk.Tk):
    def __init__(self):

        tk.Tk.__init__(self)
        self.geometry("350x200")
        self.txt_frame = tk.Frame(self)
        self.txt_frame.grid(row=1, column=1)
        self.txt_box = tk.Text(self.txt_frame, width=40, height=15)
        self.txt_box.pack()
        self.update_textbox()

    def update_textbox(self):
        self.txt_box.delete(1.0, "end")
        for ndex, data_set in enumerate(list_of_file_data):
            if data_set[2] == True:
                self.txt_box.insert("end", "{}".format(data_set[0]))
                self.txt_box.window_create(self.txt_box.index("end"), window = tk.Button(self.txt_box, text="F", command=lambda x=ndex: self.toggle_data(x)))
                self.txt_box.insert("end", "\n")
                self.txt_box.insert("end", "    {}\n\n".format(data_set[1]))
            else:
                self.txt_box.insert("end", "{}".format(data_set[0]))
                self.txt_box.window_create(self.txt_box.index("end"), window = tk.Button(self.txt_box, text="F", command=lambda x=ndex: self.toggle_data(x)))
                self.txt_box.insert("end", "\n...\n")


    def toggle_data(self, ndex):
        if list_of_file_data[ndex][2] == True:
            list_of_file_data[ndex][2] = False
        else:
            list_of_file_data[ndex][2] = True
        self.update_textbox()


if __name__ == "__main__":
    Example().mainloop()

下面的图像在文本的右侧显示了按钮,但是如果您希望将它们全部向左对齐,则比将它们向右对齐要容易得多。

如果将update_textbox()方法更改为此,它将把按钮放在左侧。

def update_textbox(self):
    self.txt_box.delete(1.0, "end")
    for ndex, data_set in enumerate(list_of_file_data):
        if data_set[2] == True:
            self.txt_box.window_create(self.txt_box.index("end"), window = tk.Button(self.txt_box, text="F", command=lambda x=ndex: self.toggle_data(x)))
            self.txt_box.insert("end", "{}".format(data_set[0]))
            self.txt_box.insert("end", "\n")
            self.txt_box.insert("end", "    {}\n\n".format(data_set[1]))
        else:
            self.txt_box.window_create(self.txt_box.index("end"), window = tk.Button(self.txt_box, text="F", command=lambda x=ndex: self.toggle_data(x)))
            self.txt_box.insert("end", "{}".format(data_set[0]))
            self.txt_box.insert("end", "\n...\n")

结果:

enter image description here

enter image description here

...

...

...

以下是我的原始示例,但我选择不删除它,因为我认为它可能对某些人有用。此示例将使用按钮作为上下文表和跟踪列表,以跟踪可以显示或不显示的内容。

import tkinter as tk

list_of_file_data = [["Data set 1!", "This is the contents of data set 1.", True],
                     ["Data set 2!", "This is the contents of data set 2.", True],
                     ["Data set 3!", "This is the contents of data set 3.", True]]

class Example(tk.Tk):
    def __init__(self):

        tk.Tk.__init__(self)
        self.geometry("350x200")
        self.tbl_view = True
        self.tbl_frame = tk.Frame(self)
        self.tbl_frame.grid(row=1, column=0, sticky="nsew")
        self.txt_frame = tk.Frame(self)
        self.txt_frame.grid(row=1, column=1)
        tk.Button(self, text="Toggle Table of context", command=self.show_hide_tbl).grid(row=0, column=0, columnspan=2, sticky="ew")
        self.txt_box = tk.Text(self.txt_frame, width=30, height=10)
        self.txt_box.pack()
        self.update_textbox()

    def update_textbox(self):
        self.tbl_frame.destroy()
        self.tbl_frame = tk.Frame(self)
        if self.tbl_view == True:
            self.tbl_frame.grid(row=1, column=0, sticky="nsew")

        self.txt_box.delete(1.0, "end")
        for ndex, data_set in enumerate(list_of_file_data):
            tk.Button(self.tbl_frame, text=data_set[0], command=lambda x=ndex: self.toggle_data(x)).pack()
            if data_set[2] == True:
                self.txt_box.insert("end", "{}\n".format(data_set[0]))
                self.txt_box.insert("end", "    {}\n\n".format(data_set[1]))

    def toggle_data(self, ndex):
        if list_of_file_data[ndex][2] == True:
            list_of_file_data[ndex][2] = False
        else:
            list_of_file_data[ndex][2] = True
        self.update_textbox()

    def show_hide_tbl(self):
        if self.tbl_view == True:
            self.tbl_frame.grid_forget()
            self.tbl_view = False
        else:
            print("Else")
            self.tbl_frame.grid(row=1, column=0, sticky="nsew")
            self.tbl_view = True


if __name__ == "__main__":
    Example().mainloop()