【问题标题】:How to create a Dynamic Scrollable Grid on tkinter如何在 tkinter 上创建动态可滚动网格
【发布时间】:2021-04-13 05:30:15
【问题描述】:

当我说动态网格时,我说的是根据窗口宽度调整列数(如引导程序)的网格,因此它必须相应地调整“卡片”,当我说可滚动时......好吧...更容易理解。

我尝试了两种方法:

  1. 创建一个动态网格,然后使其可滚动。
  2. 创建一个可滚动的网格,然后使其动态化。

我在这两个方面都失败了!我发现为了可滚动,网格不能在简单的框架中,它必须在 Canvas 中。而对于画布,我很难让它充满活力。

下面是我的动态网格代码

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

    def re_grid(self, event=None):
        grid_width = self.winfo_width()
        slaves = self.grid_slaves()
        slaves_width = slaves[1].winfo_width()
        cols = grid_width // slaves_width
        if (cols == self.columns) | (cols == 0):  
            return
        for i, slave in enumerate(reversed(slaves)):
            slave.grid_forget()
            slave.grid(row=i // cols, column=i % cols)
        self.columns = cols

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

        tk.Label(self, text="Hello").pack()
   
def main():
    root = tk.Tk()
    frame = DynaGrid(root)
    frame.pack(fill=tk.BOTH, expand=True)

CardFrame(frame).grid() 
CardFrame(frame).grid()
CardFrame(frame).grid() 
CardFrame(frame).grid()
CardFrame(frame).grid() 
CardFrame(frame).grid()
CardFrame(frame).grid() 
CardFrame(frame).grid()
root.mainloop()

if __name__ == '__main__':
    main()

我不会浪费其他人的时间在这里发布我凌乱的画布代码,而是我有一个来自 https://blog.tecladocode.com/tkinter-scrollable-frames/ 我已经更改为使用我的“卡片”而不是标签。

import tkinter as tk
from tkinter import ttk


class ScrollableFrame(ttk.Frame):
    def __init__(self, container, *args, **kwargs):
        super().__init__(container, *args, **kwargs)
        canvas = tk.Canvas(self)
        scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
        self.scrollable_frame = ttk.Frame(canvas)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")

        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

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)
  
root = tk.Tk()
frame = ScrollableFrame(root)

for i in range(50):

    TestFrame(frame.scrollable_frame).grid()

frame.pack()
root.mainloop()

要制作动态可滚动画布,这里的棘手部分是在画布内使用 re_grid 函数。我不知道如何像在 dynaGrid 代码中那样正确获取窗口宽度。

最后我想要这两个代码的混搭;一个类,它是某种带有横向滚动动态网格的框架。

【问题讨论】:

  • 请不要问一个问题,然后发布其他人的代码,这些代码没有做你的代码正在做的事情。花点时间为您的问题创建一个合适的minimal reproducible example。另外,请发布语法正确的代码。您的第一个代码块有缩进错误。
  • 您是真的想创建一个列宽相等的网格,还是只在一行内容不合适时将其包裹起来就足够了?
  • ident 已修复.. 抱歉.. 是的,我的网格将有等宽的列。在生产代码中,它将是 conf 类的属性
  • 它不起作用,这样滚动与行不匹配......你说的画布周围的反转方式变成了“瓷砖”
  • 我不知道您所说的“滚动与行不匹配”是什么意思。如果您有一个按照您想要的方式运行的框架,您只需将该框架添加到画布,以便您可以使用画布的滚动功能。

标签: python python-3.x tkinter grid-layout tkinter-canvas


【解决方案1】:

你的画布是你班级中的一个框架, 因此,您需要做的是将您的重新网格功能绑定到您的主框架并保持可滚动框架配置回调不变。然后更改画布内的网格,而不是重新网格功能中的“动态网格”。就那么简单! 而且我认为更容易说:我想创建一个行为类似于文件资源管理器的窗口

import tkinter as tk
from tkinter import ttk


class ScrollableFrame(ttk.Frame):
    def _init_(self, container, *args, **kwargs):
        super()._init_(container, *args, **kwargs)
        canvas = tk.Canvas(self)
        scrollbar = ttk.Scrollbar(self, orient="vertical", command=canvas.yview)
        self.scrollable_frame = ttk.Frame(canvas)
        self.columns=0

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(
                scrollregion=canvas.bbox("all")
            )
        )

        self.bind('<Configure>', self.regrid)

        canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")

        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

    def regrid(self, event=None):
        print(type(self))
        grid_width = self.winfo_width()
        slaves = self.scrollable_frame.grid_slaves()
        print(len(slaves))
        slaves_width = slaves[1].winfo_width()
        cols = grid_width // slaves_width
        if (cols == self.columns) | (cols == 0):  # if the column number has not changed, abort
            return
        for i, slave in enumerate(reversed(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)


root = tk.Tk()
frame = ScrollableFrame(root)

for i in range(10):
    TestFrame(frame.scrollable_frame).grid()
    TestFrame(frame.scrollable_frame).grid()

frame.pack(side="left", fill=tk.BOTH, expand=True)
root.mainloop()

【讨论】:

    猜你喜欢
    • 2021-12-02
    • 1970-01-01
    • 2021-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多