0

我一直在使用tkinter 和 tkinter.ttk在 python 中制作这个下载器应用程序,并在应用程序中添加了一个最近的功能,供用户查看程序以前执行的操作的日志。它工作正常,但是,我最近发现了一个错误。

我有一个设置按钮,它创建另一个 Toplevel,然后您可以管理默认目录并使用三个ttk.Radiobuttons将应用程序的模式切换为灯光或夜间模式或自定义主题,但每当我点击前两个单选按钮时(前两个负责将主题从浅色模式切换到深色模式,反之亦然)我的 ttk.treeview 的宽度被无缘无故地添加了一个。奇怪的是,它不会发生在第三个单选按钮上,负责制作自定义模式。

我尝试为日志的顶层设置一个maxsize,但它会影响 ttk.treeview 本身。为什么会这样?我怎样才能防止这种情况?

我的应用程序的模拟(这只是一个演示,所以我没有编写整个主题代码):

from tkinter import *
from tkinter import colorchooser
from tkinter import ttk

columns = ("Operation", "URL", "File Path", "Status", "Start Date", "End Date")
log_data = [("Download (File)", "https://www.youtube.com", "C:/Users/Mypc/Downloads/youtube.html", "Finished", "2021-03-30 13:15:30", "2021-03-30 13:15:33"),
            ("Format Fetch", "https://www.youtube.com/watch?v=xxNxqveseyI", "------", "Finished", "2021-03-30 13:15:30", "2021-03-30 13:15:33")]
font_color, bg_color = "black", "white"
root = Tk()
root.configure(bg=bg_color)
root.resizable(False, False)
night_on = IntVar(value=1)
style = ttk.Style()
style.configure("Treeview", rowheight=25, font=('Arial', 10))
style.configure("Treeview.Heading", font=('Arial', 10))
style.configure("TLabel", foreground=font_color, background=bg_color)
style.configure('my.TButton', font=('Helvetica', 20, 'italic'))
style.configure("TRadiobutton", foreground=font_color, background=bg_color, font=('Arial', 10))
font_color_var = StringVar(value=f"Current font color:  \t  {font_color}")
bg_color_var = StringVar(value=f"Current background color:  \t  {bg_color}")
log_top = Toplevel(root)
log_top.withdraw()
log_top.resizable(False, False)
log_fr = Frame(log_top)
log_scroll = ttk.Scrollbar(log_fr, orient=VERTICAL)
log_tree = ttk.Treeview(log_fr, selectmode="browse", yscrollcommand=log_scroll.set, height=12, columns=columns)
log_scroll.config(command=log_tree.yview)


def clear_records():
    for child in log_tree.get_children():
        log_tree.delete(child)


clr_log_btn = ttk.Button(log_top, text="Clear Log", takefocus=False, style="my.TButton", command=clear_records)
log_tree.column("#0", width=0, stretch=NO)
log_tree.column("Operation", width=100, anchor=CENTER)
log_tree.column("URL", width=100, anchor=CENTER)
log_tree.column("File Path", width=100, anchor=CENTER)
log_tree.column("Status", width=80, anchor=CENTER)
log_tree.column("Start Date", width=126, anchor=CENTER)
log_tree.column("End Date", width=126, anchor=CENTER)

for head in columns:
    log_tree.heading(head, text=head, anchor=CENTER)

for item_indices, element in enumerate(log_data):
    log_tree.insert(parent='', index=0, iid=item_indices, values=element)


log_tree.pack(side=LEFT)
log_scroll.pack(side=RIGHT, fill=Y)
clr_log_btn.pack(side=BOTTOM, fill=X)
log_fr.pack()
log_top.protocol("WM_DELETE_WINDOW", log_top.withdraw)
log_lbl = Label(root, text="Show Log", fg="blue", bg=bg_color, cursor="hand2")


def show_log(event):
    if log_top.state() == "withdrawn":
        log_top.deiconify()
    elif log_top.state() == "normal":
        log_top.focus_set()


def settings_win():
    settings_top = Toplevel(root, bg=bg_color)
    settings_top.resizable(False, False)

    def set_night():
        global bg_color, font_color
        bg_color = "black"
        font_color = "white"
        settings_top.config(bg=bg_color)
        style.configure("TLabel", foreground=font_color, background=bg_color)
        style.configure("TRadiobutton", foreground=font_color, background=bg_color)

    def set_light():
        global bg_color, font_color
        bg_color = "white"
        font_color = "black"
        settings_top.config(bg=bg_color)
        style.configure("TLabel", foreground=font_color, background=bg_color)
        style.configure("TRadiobutton", foreground=font_color, background=bg_color)

    def set_custom():
        global font_color, bg_color
        color_fr = Toplevel(root, bg=bg_color)
        color_fr.resizable(False, False)
        current_font_color = ttk.Label(color_fr, textvariable=font_color_var)
        current_bg_color = ttk.Label(color_fr, textvariable=bg_color_var)

        def change_color(name):
            global font_color, bg_color
            new_color = colorchooser.askcolor()[1]
            if new_color is not None:
                if name == "font":
                    font_color = new_color
                    font_color_var.set(f"Current font color:  \t  {font_color}")
                    style.configure("TLabel", foreground=font_color)
                    style.configure("TRadiobutton", foreground=font_color)
                elif name == "bg":
                    bg_color = new_color
                    bg_color_var.set(f"Current background color:  \t  {bg_color}")
                    color_fr.config(bg=bg_color)
                    style.configure("TLabel", background=bg_color)
                    style.configure("TRadiobutton", background=bg_color)

        change_font = ttk.Button(color_fr, text="Change! ", command=lambda: change_color("font"),
                                 takefocus=False)
        change_bg = ttk.Button(color_fr, text="Change! ", command=lambda: change_color("bg"), takefocus=False)
        current_font_color.grid(row=0, column=0, pady=(10, 0), padx=5)
        change_font.grid(row=0, column=1, padx=(0, 7))
        current_bg_color.grid(row=1, column=0, pady=(10, 0), padx=5)
        change_bg.grid(row=1, column=1, padx=(0, 7))

    night_mode = ttk.Radiobutton(settings_top, text="Night Mode", variable=night_on, value=0,
                                 command=set_night, takefocus=False)
    light_mode = ttk.Radiobutton(settings_top, text="Light Mode", variable=night_on, value=1,
                                 command=set_light, takefocus=False)
    custom_mode = ttk.Radiobutton(settings_top, text="Custom Mode", variable=night_on, value=2,
                                  command=set_custom, takefocus=False)

    night_mode.grid(row=0, column=0)
    light_mode.grid(row=1, column=0)
    custom_mode.grid(row=2, column=0)


log_lbl.bind("<Button-1>", show_log)
log_lbl.pack(side=LEFT, pady=30, padx=30)
settings_btn = ttk.Button(root, text="Open Settings", takefocus=False, command=settings_win)
settings_btn.pack(side=RIGHT, padx=30, pady=30)
root.focus_set()
root.mainloop()
4

1 回答 1

1

我想我找到了解决你问题的方法。首先,我缩小了您的代码以使其更易于调试:

import tkinter as tk
from tkinter import ttk

columns = ("1", "2", "3")
font_color, bg_color = "black", "white"

def change_theme():
    global bg_color, font_color
    # Switches the values of `bg_color` and `font_color`
    bg_color, font_color = font_color, bg_color
    root.config(bg=bg_color)
    style.configure("TLabel", fg=font_color, bg=bg_color)


root = tk.Tk()

style = ttk.Style()

tree = ttk.Treeview(root, columns=columns)
tree.pack()

button = tk.Button(root, text="Click me", command=change_theme)
button.pack()

root.mainloop()

再次查看您的代码后,我注意到您的代码与标题stretch=NO相同。我决定将它应用于所有标题,如下所示:stretch=False#0

tree.column("#0", stretch=False)
for column_name in columns:
    tree.column(column_name, stretch=False)

它解决了你的问题。在查看文档后,ttk.TreeView我注意到它对拉伸参数的说明:“如果此选项为 True,则在调整小部件大小时将调整列的宽度。默认设置为 1。” 由此我得出结论,由于某种原因style.configure("TLabel", ...)会更改树视图的宽度,从而触发所有列调整大小。

我不太了解TreeViewStyles无法告诉您为什么会发生这种情况,但是如果有人知道他们可以编辑我的答案。

于 2021-04-03T13:35:28.403 回答