簡體   English   中英

Tkinter Grid 動態布局

[英]Tkinter Grid Dynamic Layout

我想創建一個網格布局,用一個網格填充第一行,直到它在窗口中用完空間,並將項目動態移動到下面的行(如文本換行)。 隨着窗口寬度的調整,網格也會調整以適應。 不需要調整大小的框。 我打算保持每個小盒子的大小,但改變布局放置每個盒子的位置。

我想通過測量框架的寬度可以實現此功能,如果(框數)*(每個框的寬度)超過寬度,則移至下一行。 我只是想知道是否有更好的方法內置我不理解。

如果以上是唯一的選擇,那么更新它的最佳方法是什么? 我是否必須在窗口調整大小或其他方面設置事件? 看起來我不應該重新設計布局管理器,這就是感覺。 我只是想檢查是否已經內置了類似的功能。網格看起來像一個強大的布局管理器,但我一直找不到那個選項。

下面的圖片描述了我想要使用網格布局在單個框架上使用相同的一組 6 個框的行為。

窗口的寬度足以容納所有 6 個框,因此它們都適合第 1 行。然后它們會隨着窗口大小的變化而調整。 在此處輸入圖片說明

在此處輸入圖片說明 在此處輸入圖片說明

如果您計划強制每個框具有統一的大小,最簡單的解決方案是使用文本小部件作為容器,因為它具有內置的換行能力。

這是一個工作示例。 單擊“添加”按鈕以添加其他框。 調整窗口大小以查看它們隨着窗口的增長和收縮而自動換行。

import Tkinter as tk
import random

class DynamicGrid(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.text = tk.Text(self, wrap="char", borderwidth=0, highlightthickness=0,
                            state="disabled")
        self.text.pack(fill="both", expand=True)
        self.boxes = []

    def add_box(self, color=None):
        bg = color if color else random.choice(("red", "orange", "green", "blue", "violet"))
        box = tk.Frame(self.text, bd=1, relief="sunken", background=bg,
                       width=100, height=100)
        self.boxes.append(box)
        self.text.configure(state="normal")
        self.text.window_create("end", window=box)
        self.text.configure(state="disabled")

class Example(object):
    def __init__(self):
        self.root = tk.Tk()
        self.dg = DynamicGrid(self.root, width=500, height=200)
        add_button  = tk.Button(self.root, text="Add", command=self.dg.add_box)

        add_button.pack()
        self.dg.pack(side="top", fill="both", expand=True)

        # add a few boxes to start
        for i in range(10):
            self.dg.add_box()

    def start(self):
        self.root.mainloop()

Example().start()

這是一個工作示例:

import Tkinter as tk

class AutoGrid(tk.Frame):
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        self.columns = None
        self.bind('<Configure>', self.regrid)

    def regrid(self, event=None):
        width = self.winfo_width()
        slaves = self.grid_slaves()
        max_width = max(slave.winfo_width() for slave in slaves)
        cols = width // max_width
        if cols == self.columns: # if the column number has not changed, abort
            return
        for i, slave in enumerate(slaves):
            slave.grid_forget()
            slave.grid(row=i//cols, column=i%cols)
        self.columns = cols

class TestFrame(tk.Frame):
    def __init__(self, master=None, **kwargs):
        tk.Frame.__init__(self, master, bd=5, relief=tk.RAISED, **kwargs)

        tk.Label(self, text="name").pack(pady=10)
        tk.Label(self, text=" info ........ info ").pack(pady=10)
        tk.Label(self, text="data\n"*5).pack(pady=10)

def main():
    root = tk.Tk()
    frame = AutoGrid(root)
    frame.pack(fill=tk.BOTH, expand=True)

    TestFrame(frame).grid() # use normal grid parameters to set up initial layout
    TestFrame(frame).grid(column=1)
    TestFrame(frame).grid(column=2)
    TestFrame(frame).grid()
    TestFrame(frame).grid()
    TestFrame(frame).grid()
    root.mainloop()

if __name__ == '__main__':
    main()

請注意,這會破壞網格管理器的 rowspan 和 columnspan 功能。

這是 Bryan 答案的簡化版本,沒有課程,還有一些額外的評論,供那些感到困惑並試圖將其快速實施到他們自己的項目中的人使用。

from tkinter import *
import tkinter as tk

#Create main window
root = tk.Tk()

#Create WidgetWrapper
widgetWrapper = tk.Text(root, wrap="char", borderwidth=0,highlightthickness=0,state="disabled", cursor="arrow") 
#state = "disabled" is to disable text from being input by user
#cursor = "arrow" is to ensure when user hovers, the "I" beam cursor (text cursor) is not displayed

widgetWrapper.pack(fill="both", expand=True)

def additem():
    item = Label(bd = 5, relief="solid", text="O", bg="red") #Create the actual widgets
    widgetWrapper.window_create("end", window=item) #Put it inside the widget wrapper (the text)

# add a few boxes to start
for i in range(10):
    additem()

#Not needed to implement in other code, just an add button
add_button  = tk.Button(root, text="Add", command=additem)
add_button.pack()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM