【问题标题】:tkinter.Frame.Grid sizing not displaying correctlytkinter.Frame.Grid 大小未正确显示
【发布时间】:2019-12-11 23:06:18
【问题描述】:

您好,我正在制作一个表格,其中包含用于命名列的文本标题、用于存储数据的单元格和滚动。

我遇到的问题是我的表格显示不正确。应该发生的是标题应该显示在上方,而下方没有其他空间。 (除了我添加的小填充)单元格在标题下方正确显示。

滚动适用于 y 方向的单元格。滚动也适用于单元格和标题的 x 方向。

将单元格添加到框架的函数只需创建然后使用 grid(row, column) 添加 标题只有 1 行,所以不应该有空格。

import tkinter as tk
import collections
from enum import Enum

window = tk.Tk() # Root (main) window

def main():
    window.title('Table')
    window.geometry("1024x600")
    window.update_idletasks()
    table_frame = tk.Frame(window, background='black')
    table_frame.pack(fill='x')
    table = Table(table_frame, 30, 15)
    print(id(table))

    window.mainloop()

class Table:

    def __init__(self, frame, rowCount, columnCount):
        self._rowCount = rowCount
        self._columnCount = columnCount

        main_frame = tk.Frame(frame, bg='blue')
        main_frame.pack(fill='both')

        self._headerCanvas = tk.Canvas(main_frame)
        self._headerCanvas.grid(row=0, column=0, pady=1, sticky='ew')

        self._cellCanvas = tk.Canvas(main_frame)
        self._cellCanvas.grid(row=1, column=0, sticky='ew')

        scroll_bar_y = tk.Scrollbar(main_frame, orient=tk.VERTICAL, command=self._cellCanvas.yview)
        scroll_bar_y.grid(row=1, column=1, padx=1, sticky='ns')

        scroll_bar_x = tk.Scrollbar(main_frame, orient=tk.HORIZONTAL, command=self.xViewScroll)
        scroll_bar_x.grid(row=2, column=0, pady=1, sticky='ew')

        main_frame.grid_columnconfigure(0, weight=1)
        main_frame.grid_rowconfigure(1, weight=1)

        self._cellCanvas.configure(xscrollcommand=scroll_bar_x.set, yscrollcommand=scroll_bar_y.set) #, width=(main_frame.winfo_width()-scroll_bar_y.winfo_width()))

        header_frame = tk.Frame(self._headerCanvas)
        self._headers = Table.ColumnHeaders(header_frame, self._columnCount)
        cell_frame = tk.Frame(self._cellCanvas)
        self._cells = Table.Cells(cell_frame, self._rowCount, self._columnCount)

        self._headerCanvas.create_window(0, 0, window=header_frame, anchor='nw')
        self._headerCanvas.update_idletasks()
        self._cellCanvas.create_window(0, 0, window=cell_frame, anchor='nw')
        self._cellCanvas.update_idletasks()
        self._headerCanvas.configure(scrollregion=self._cellCanvas.bbox("all"))
        self._cellCanvas.configure(scrollregion=self._cellCanvas.bbox("all"))

    def xViewScroll(self, *args):
        self._headerCanvas.xview(*args)
        self._cellCanvas.xview(*args)


    class Cells:

        class Types(Enum):
            Entry = 0
            Button = 1

        class Cell:
            def __init__(self, widget, text=''):
                self._text = text
                self._widget = widget


            def getWidget(self):
                return self._widget

            def setWidget(self, widget):
                self._widget = widget

            widget = property(getWidget, setWidget, "Get and set the widget of a cell.")


        def __init__(self, frame, rows, columns, cellTypes=Types.Entry):
            self._cells = [[],[]]

            for r in range(rows):
                self._cells.append([])
                for c in range(columns):
                    self._cells[r].append(c)
                    if cellTypes == Table.Cells.Types.Entry:
                        self._cells[r][c] = Table.Cells.Cell(tk.Entry(frame, width=15))
                    elif cellTypes == Table.Cells.Types.Button:
                        self._cells[r][c] = Table.Cells.Cell(tk.Button(frame, width=12))

                    self._cells[r][c].widget.grid(row=r, column=c)


        def getCell(self, row, column):
            return self._cells[row][column]

        def setCell(self, row, column, cell):
            self._cells[row][column] = cell

        cells = property(getCell, setCell, "Get and set a cell in the table.")


    class ColumnHeaders:
        def __init__(self, widget, columnCount):
            self._widget = widget
            self._columnCount = columnCount
            self._headers = Table.Cells(self._widget, 1, self._columnCount, cellTypes=Table.Cells.Types.Button)
main()

这就是它们目前的显示方式。

调整屏幕大小后,这就是原件的样子。标题就在下面的单元格上方,只有填充空间。

如果我再缩小一点,它会导致另一个问题,滚动条和标题会从视图中消失。 但是,右侧的滚动条永远不会消失。 (我猜这是因为我不能再缩小屏幕了。

这就是 main_frame.grid_rowconfigure(1, weight=1) 发生的情况 在将大小调整为较小的窗口后会导致此问题。

【问题讨论】:

  • 此代码不会运行。当我添加足够的代码使其工作时,我得到AttributeError: type object 'Table' has no attribute 'ColumnHeaders'
  • 我没有发布所有代码,但我回家后可以。我只发布了控制布局的代码部分。其他的只是使用来自 tkinter 的按钮或条目来填充。
  • 我们不需要“所有代码”,我们只需要复制问题即可。如果ColumnHeaders 不是重现布局问题所必需的,只需将其删除即可。
  • @deathismyfriend:你需要绑定事件"<Configure>",因为Canvas不跟随Frame的大小。像这样的东西:use canvas to create dynamically window with scroll bar
  • @BryanOakley 我用产生问题所需的所有代码更新了上面的代码。

标签: python tkinter tkinter-canvas tkinter-layout


【解决方案1】:

问题Frame 网格大小显示不正确

你被误导了,header_frame 不是使用.grid(...)布局的。
使用.create_window(... 将小部件添加到Canvas 的固定位置0, 0, anchor='nw'。因此,没有 “网格布局管理器” 魔法,如自动调整大小,发生了。


为什么会得到这个布局?
注意main_frame == 'blue'_headerCanvas == 'lightgreen'_cellCanvas == 'red'


布局:A                          布局:B                        布局:C                            布局:D

        self._headerCanvas = tk.Canvas(main_frame, bg='lightgreen')
        self._headerCanvas.grid(row=0, column=0, pady=1, sticky='ew')

        main_frame.grid_rowconfigure(1, weight=1)

        self._cellCanvas = tk.Canvas(main_frame, bg='red')
        self._cellCanvas.grid(row=1, column=0, sticky='ew')

布局:A: 您可以使用默认的 height 创建两个 Canvas。因此,您可以使用 “网格布局管理器” 获得类似的布局。

布局:B: 将项目添加到Canvas,此处为单元格Frame,不会更改布局中的任何内容。


布局:C: 将Canvas heightheader_frame height 结果同步。

  1. 使用.bind('<Configure>'

    header_frame = tk.Frame(self._headerCanvas)
    header_frame.bind('<Configure>', self.on_configure)
    
    def on_configure(self, event):
        # Sync _headerCanvas height with header_frame height
        w = event.widget
        self._headerCanvas.configure(height=w.winfo_height())
    
  2. 使用.update_idletask()

        header_frame = tk.Frame(self._headerCanvas)
        self._headers = Table.ColumnHeaders(header_frame, self._columnCount)
        root.update_idletasks()
        self._headerCanvas.configure(height=header_frame.winfo_height())
    

仍然不是您想要的?
布局:D: 您通过以下方式让.grid(row=1 尽可能地增长:

    main_frame.grid_rowconfigure(1, weight=1)

但是您不允许 Canvas 使用 sticky='ns' 增长。这导致上方/下方的'blue' 空间。更改为sticky='nsew'

【讨论】:

  • 谢谢。你的方法2效果很好。但是由于某种原因,您的方法 1. 使用 bind 在标题下方创建了一个奇怪的栏。我将新图片添加到我的问题中,并用红线表示错误。你能告诉我为什么会这样吗?
  • @deathismyfriend:height 值不同?将w.winfo_height() 的输出与header_frame.winfo_height() 进行比较。该值取决于您调用.update_idletasks()._headerCanvas.configure(... 的代码行。您使用的是pady=1,但这两者都一样。
  • 我试过高度。这似乎是另外一回事,因为它实际上在这两种方法中都是如此。最大化时,它几乎显示为边框。我已经更新了你可以在那里看到的最后一张图片。我已将所有背景更改为蓝色,但仍然显示。
  • 我修复了它是边框出现的问题。非常感谢您的帮助。
猜你喜欢
  • 2022-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 1970-01-01
  • 2022-01-21
  • 2017-01-08
相关资源
最近更新 更多