首页 > 解决方案 > 如何使 python tkinter 小部件出现在框架的右侧并向左增长?

问题描述

当前行为,将 LabelFrame 小部件(带有自己的标签和图片子项)添加到另一个名为“Test puts buffs...”的 LabelFrame 中。LabelFrame 小部件被添加到 LabelFrame 的左侧并“增长”到右侧。想要的行为是小部件出现在框架的右侧并在左侧“增长”。

似乎无法通过锚定或粘性设置到达那里。这种“向左增长”如何完成,并且仍然保留按名称或剩余时间排序的能力?

当前行为 gif:

正确成长

想要的行为(用油漆模拟):

在此处输入图像描述

代码(取出图像内容,因此不需要运行文件):

import tkinter as tk
from tkinter import ttk
from PIL import ImageTk, Image
import time

class MainFrame(tk.Frame):
    def __init__(self, container):
        super().__init__(container)

        self.grid(column=0, row=0)

        self.buffs_list_frames = []

        self.button1 = ttk.Button(self)
        self.button1['text'] = "Simulate frame list appended True Strike"
        self.button1['command'] = lambda: self.buffs_frame_list_is_appended(["True Strike", time.time() + 9])
        self.button1.grid(column=0, row=0)

        self.button2 = ttk.Button(self)
        self.button2['text'] = "Simulate frame list appended Bulls"
        self.button2['command'] = lambda: self.buffs_frame_list_is_appended(["Bulls", time.time() + 1080])
        self.button2.grid(column=0, row=1)

        self.button0 = ttk.Button(self)
        self.button0['text'] = "Simulate frame list appended Endurance"
        self.button0['command'] = lambda: self.buffs_frame_list_is_appended(["Endurance", time.time() + 1080])
        self.button0.grid(column=0, row=2)

        self.button3 = ttk.Button(self)
        self.button3['text'] = "Simulate frame list put into .grid() and displayed"
        self.button3['command'] = lambda: self.buffs_display_nicely()
        self.button3.grid(column=0, row=3)

        self.button4 = ttk.Button(self)
        self.button4['text'] = "START loops of time passing"
        self.button4['command'] = lambda: self.buffs_loop_time_passing()
        self.button4.grid(column=0, row=4)

        self.test_label_frame = ttk.LabelFrame(self, text="Testing putting buffs into a frame with grid")
        self.test_label_frame.grid(column=1, row=0)


    def buffs_loop_time_passing(self):
        for x in self.buffs_list_frames:
            x.buff_timer.set(f"{x.buff_birthday - time.time():.1f}s")
            if x.buff_birthday < time.time() + 6:
                x['background'] = 'red'
            if x.buff_birthday < time.time():
                self.buffs_list_frames.remove(x)
                x.destroy()
        self.after(1000, self.buffs_loop_time_passing)

    def buffs_frame_list_is_appended(self, added_buff):
        """ makes the buff frame and adds to the list of frame widgets
        """ 

        self.buff_frame = tk.LabelFrame(self.test_label_frame, borderwidth=1, text=added_buff[0][0:4], labelanchor="n") 

        # self.buff_frame.buff_image_reference = ImageTk.PhotoImage(Image.open(added_buff[2]))
        # self.buff_frame.buff_image_label = ttk.Label(self.buff_frame, image=self.buff_frame.buff_image_reference)
        # self.buff_frame.buff_image_label.image_keep = self.buff_frame.buff_image_reference
        # self.buff_frame.buff_image_label.grid(column=0, row=0)
        self.buff_frame.buff_birthday = added_buff[1]
        self.buff_frame.buff_timer = tk.StringVar()
        self.buff_frame.buff_timer.set(f"{self.buff_frame.buff_birthday - time.time():.1f}s")
        self.buff_frame.buff_label = ttk.Label(self.buff_frame, textvariable=self.buff_frame.buff_timer)
        self.buff_frame.buff_label.grid(column=0, row=1)
        self.buffs_list_frames.append(self.buff_frame)

        self.buffs_display_nicely()

    def buffs_display_nicely(self):
        """ takes the list of frames, sorts by name, and .grids()s them into the test frame
        """
        self.buffs_list_frames = sorted(self.buffs_list_frames, key=lambda z: z['text'])
        print(f"sorted? {self.buffs_list_frames}")
        j = 0
        for x in self.buffs_list_frames:
            x.grid(row=0, column=j)
            j += 1

class App(tk.Tk):
    def __init__(self):
        super().__init__()
        # configure the root window
        self.title('NWN Buff Watcher')
        self.geometry('300x50')

if __name__ == "__main__":
    app = App()
    main_frame = MainFrame(app)
    app.mainloop()

标签: pythontkinter

解决方案


试试这个(使用@acw1668 的建议):

import tkinter as tk
from tkinter import ttk
from PIL import ImageTk, Image
import time

class MainFrame(tk.Frame):
    def __init__(self, container):
        super().__init__(container)

        self.buffs_list_frames = []
        self.buttons_frame = tk.Frame(self)
        self.buttons_frame.pack(fill="both", side="left")

        self.button1 = ttk.Button(self.buttons_frame, text="Simulate frame list appended True Strike",
                                  command=lambda: self.buffs_frame_list_is_appended("True Strike", 9))
        self.button1.grid(column=0, row=0)

        self.button2 = ttk.Button(self.buttons_frame, text="Simulate frame list appended Bulls",
                                  command=lambda: self.buffs_frame_list_is_appended("Bulls", 1080))
        self.button2.grid(column=0, row=1)

        self.button0 = ttk.Button(self.buttons_frame, text="Simulate frame list appended Endurance",
                                  command=lambda: self.buffs_frame_list_is_appended("Endurance", 1080))
        self.button0.grid(column=0, row=2)

        #self.button3 = ttk.Button(self.buttons_frame, text="Order items", command=self.order_items)
        #self.button3.grid(column=0, row=3)

        self.button4 = ttk.Button(self.buttons_frame, text="START loops of time passing",
                                  command=self.buffs_loop_time_passing)
        self.button4.grid(column=0, row=4)

        self.test_label_frame = ttk.LabelFrame(self, text="Testing putting buffs into a frame with grid")
        self.test_label_frame.pack(side="right")

    def buffs_loop_time_passing(self):
        for x in self.buffs_list_frames:
            x.buff_timer.set(f"{x.buff_birthday - time.time():.1f}s")
            time_now = time.time()
            if x.buff_birthday < time_now + 6:
                x.config(bg="red")
            if x.buff_birthday < time_now:
                self.buffs_list_frames.remove(x)
                x.destroy()
        self.after(100, self.buffs_loop_time_passing)

    def buffs_frame_list_is_appended(self, added_buff, time_alive):
        """ makes the buff frame and adds to the list of frame widgets
        """ 
        buff_frame = tk.LabelFrame(self.test_label_frame, borderwidth=1,
                                   text=added_buff[:4], labelanchor="n") 

        # buff_frame.buff_image_reference = ImageTk.PhotoImage(Image.open(added_buff[2]), master=self)
        # buff_frame.buff_image_label = ttk.Label(buff_frame, image=buff_frame.buff_image_reference)
        # buff_frame.buff_image_label.image_keep = buff_frame.buff_image_reference
        # buff_frame.buff_image_label.grid(column=0, row=0)
        buff_frame.buff_birthday = time.time() + time_alive
        buff_frame.buff_timer = tk.StringVar(master=self)
        buff_frame.buff_timer.set(f"{buff_frame.buff_birthday - time.time():.1f}s")
        buff_frame.buff_label = ttk.Label(buff_frame,
                                          textvariable=buff_frame.buff_timer)
        buff_frame.buff_label.grid(column=0, row=1)
        self.buffs_list_frames.append(buff_frame)

        self.order_items()

    def order_items(self):
        self.buffs_list_frames = sorted(self.buffs_list_frames, key=lambda z: z['text'], reverse=True)
        for x in self.buffs_list_frames:
            x.pack_forget()
            x.pack(side="right")


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        # configure the root window
        self.title("NWN Buff Watcher")
        # self.geometry("300x50")


if __name__ == "__main__":
    app = App()
    main_frame = MainFrame(app)
    main_frame.pack()
    app.mainloop()

我对您的代码进行了一些更改。最主要的是我删除buffs_display_nicely并添加了buff_frame.pack(side="right"). side="right"告诉tkinter从右到左添加小部件。

如果你添加一个类而不是使用buff_frame.buff_birthday, buff_frame.buff_timer, ,你也可以大大改进你的代码。它也会让你的生活更轻松


推荐阅读