为什么我的tkinter布局会发生变化?

时间:2018-02-05 00:25:29

标签: python tkinter

我制作了这个tkinter应用程序,我有一个错误,布局发生了变化,底部的按钮消失了。

我无法100%重现该错误。它发生在随机时间。 因此,此SSCCE可能包含超出其需要的内容。它比我原来的应用程序还要少很多。

from random import random
from threading import Thread, Lock
from time import sleep
from tkinter import Tk, LEFT, RIGHT, BOTH, X, Y, Listbox, Scrollbar, VERTICAL, END
from tkinter.ttk import Frame, Button, Style, Entry


class ListManager:
    def __init__(self, ui):
        self.entry_list = []

        self.ui = ui  # to notify of list update

        self.timer = ListManager.interval + 1
        self.stop = False

    interval = 1  # between updates

    @staticmethod
    def api_request() -> dict:
        new_list = ["line"]
        while random() > .4:
            new_list.append("line")
        return {"data": new_list}

    def get_entries(self):
        r = self.api_request()

        self.entry_list = []

        for line in r["data"]:
            self.entry_list.append(line)

    def run(self):
        self.timer = ListManager.interval + 1
        while not self.stop:
            if self.timer > ListManager.interval:
                self.get_entries()

                if self.ui is None:
                    print("entries:", len(self.entry_list))
                    for entry in self.entry_list:
                        print(entry)
                else:
                    self.ui.receive(self.entry_list)
                self.timer = 0
            else:
                self.timer += 1
            sleep(1)


class UI(Frame):
    def __init__(self):
        super().__init__()

        self.style = Style()

        self.listbox = None
        self.name_entry = None
        self.entries = []
        self.mutex = Lock()

        self.init_pack()

    def init_pack(self):
        # TODO: investigate open button disappearing (probably need to repack in receive function)
        self.master.title("list")
        self.style.theme_use("default")

        add_streamer_frame = Frame(self)
        add_button = Button(add_streamer_frame, text="Add Line")
        add_button.pack(side=RIGHT, padx=5, pady=5)
        self.name_entry = Entry(add_streamer_frame)
        self.name_entry.pack(fill=X, padx=5, expand=True)
        add_streamer_frame.pack(fill=X)

        list_frame = Frame(self)
        self.listbox = Listbox(list_frame, height=20)
        self.listbox.configure(font=("Courier New", 12, "bold"))
        scrollbar = Scrollbar(self.listbox, orient=VERTICAL)
        self.listbox.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.listbox.yview)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.listbox.pack(fill=BOTH, padx=5, expand=True)
        list_frame.pack(fill=BOTH, expand=True)

        self.pack(fill=BOTH, expand=True)

        open_button = Button(self, text="Open")
        open_button.pack(side=LEFT, padx=5, pady=5)

    def receive(self, entries):
        self.mutex.acquire()

        self.listbox.delete(0, END)
        self.entries = []
        for entry in entries:
            self.listbox.insert(END, entry)
            self.entries.append(entry.split(" ")[0])

        self.mutex.release()


def main():
    root = Tk()
    root.geometry("800x400+300+300")
    app = UI()

    tl = ListManager(app)
    thread = Thread(target=tl.run)
    thread.start()

    root.mainloop()

    tl.stop = True
    thread.join()


if __name__ == "__main__":
    main()

这是大多数时候通常看起来的样子,应该是这样的:

normal correct

这是错误之后的样子:

bottom button disappeared

1 个答案:

答案 0 :(得分:0)

添加:

self.ui.update_idletasks()

后:

sleep(1)

替换:

self.listbox = Listbox(list_frame, height=20)

使用:

self.listbox = Listbox(list_frame)
# or self.listbox = Listbox(list_frame, height=17)

必须是在进行太多工作时,没有时间花在更新GUI上。我无法直接重现第二个屏幕截图而不会将sleep参数降低到0.001

问题的根源似乎是,每次将某些内容添加到listbox的高度(<{>} 中的winfo_height)都会被重新计算,将 down 从20个字符高度调整为17,在新插入之前总是没有时间。

基本上,您的小部件必须始终具有固定的20个字符高度,它会根据其内容和其他小部件调整大小,除非通过调用禁用来传播 self.listbox.pack_propagate(False)

添加:

print(self.ui.listbox.winfo_height())

后:

sleep(1)

看自己的身高发生了变化。