Tkinter 笔记本中的可滚动页面

Scrollable page in Tkinter Notebook

对于一个项目,我需要为N个子文件(数据集)指定一个值,这个值可以是均匀分布的(这里省略),只需要一个起始值和一个增量,或者不均匀分布,这意味着每个子文件都有自己的价值。我决定使用笔记本来区分这两种输入方法。

由于子文件的数量可以达到数百个,我需要一个滚动条,在咨询 Google 之后我发现要以这种方式使用滚动条我需要使用 canvas 并在其中放置一个框架,其中包含我想要滚动浏览的所有内容。

数字每次都可能不同,所以我决定使用一个字典,它会被迭代填充,以包含所有 'entry frames',每个包含一个标签、一个输入字段和一个变量,汇总到一个自定义 class IterEntryField。创建 class 实例后,它被打包在一个容器框架中。 for 循环结束后,容器框架被放置在一个 canvas 上,滚动条被赋予一个新的滚动区域。

from tkinter import *
from tkinter.ttk import Notebook

N = 25

class IterEntryField:
    def __init__(self, frame, label):
        self.frame = frame
        self.label = label
    def pack(self):
        self.valLabel = Label(self.frame, text = self.label, anchor = 'w')
        self.valLabel.pack(fill = X, side = LEFT)
        self.variable = StringVar()
        self.variable.set('0')
        self.valEntry = Entry(self.frame, textvariable = self.variable)
        self.valEntry.pack(fill = X, side = RIGHT)

def notebookpopup():
    zSetupWindow = Toplevel(root)
    zSetupWindow.geometry('{}x{}'.format(800, 300))
    notebook = Notebook(zSetupWindow)

    evspace = Frame(notebook)
    notebook.add(evspace, text = "Evenly spaced values")

    sOverflow = Label(evspace, text = 'Ignore this')
    sOverflow.pack()

    uevspace = Frame(notebook)
    notebook.add(uevspace, text = "Individual values")
    canvas = Canvas(uevspace, width = 800, height = 400)
    vsb = Scrollbar(canvas, command=canvas.yview)
    canvas.config(yscrollcommand = vsb.set)
    canvas.pack(side = LEFT, fill = BOTH, expand = True)
    vsb.pack(side = RIGHT, fill = Y)
    entryContainer = Frame(canvas)
    entryContainer.pack(fill = BOTH)

    frameDict = {}

    for i in range(0, N):
        frameDict[i] = Frame(entryContainer)
        frameDict[i].pack(fill = X)
        entry = IterEntryField(frameDict[i], 'Z value for subfile {}'.format(i+1))
        entry.pack()
    canvas.create_window(200, 0, window = entryContainer)
    canvas.config(scrollregion = (0,0,100,1000))
    notebook.pack(fill = X)

root = Tk()
button = Button(root, text = 'new window', command = notebookpopup)
button.pack()

root.mainloop()

我在使用这段代码时遇到了三个问题:

  1. 页面非常短,只显示了几行。

  2. 我无法计算出 create_window 中的 "proper" 偏移量。我以为 0, 0 会把它放在 canvas 的左上角,但显然 window 的左上角被取而代之。这可能可以通过 canvasxcanvasy 方法的一些反向来解决,但我还没有找到任何方法。

  3. 输入字段和标签挤在一起,而不是占据 canvas 的整个宽度。当我只使用笔记本页面框架作为容器时,这不是问题。

您的第一个问题可以追溯到您如何 pack 您的笔记本。只需将 notebook.pack(...) 更改为以下内容:

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

第二个可以通过在 create_window 方法中指定 anchor 位置来解决:

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

我不明白第三个问题是什么 - 它看起来完全符合预期。