【问题标题】:Tkinter: Embedding a populated Frame in a Canvas windowTkinter:在画布窗口中嵌入填充的框架
【发布时间】:2019-09-29 21:00:06
【问题描述】:

由于 tkinter Frame 小部件不支持滚动,因此我的初学者决定探索使用画布来容纳先前填充的框架的可能性。在我在下面重现的代码中,我有两个我无法处理的问题:为什么最左边的小部件占用这么大的空间;为什么应用程序占用所有可用的屏幕空间,甚至缩短小部件,从而不显示滚动滑块。欢迎所有建议。

#!/usr/bin/env python3
from tkinter import *
class Calc_Table(Frame):
    def __init__(self, root, cols, rows):
        Frame.__init__(self, master=root)
        self.cols = cols
        self.rows = rows
        hscrollbar = Scrollbar(orient=HORIZONTAL)
        hscrollbar.grid(row = 1, column = 0, sticky = EW)
        vscrollbar = Scrollbar(orient=VERTICAL)
        vscrollbar.grid(row = 0, column = 1, sticky = NS)
        self.canvas = Canvas(self, xscrollcommand = hscrollbar.set, yscrollcommand =                     vscrollbar.set,bg='yellow')
        self.canvas.grid(row = 0, column = 0, sticky = NSEW)
        self.canvas.grid_rowconfigure(0, weight = 1)
        self.canvas.grid_columnconfigure(0, weight = 1)
        hscrollbar.config(command = self.canvas.xview)
        vscrollbar.config(command = self.canvas.yview)
        self.initial_table = self.create_table(self.cols,self.rows)
        self.canvas_frame = self.canvas.create_window(0, 0, window = self.initial_table,
                                                  width=400, height=200, anchor=NW)
        self.canvas.update_idletasks()
        self.canvas.config(scrollregion = self.canvas.bbox('all'))

    def create_table(self, cols, rows):             # build initial table ---->
        self.cols, self.rows = cols, rows
        for c in range(self.cols):         
            for r in range(self.rows):
                if c == 0 and r == 0:
                    self.lbl = Label(self, width=6, height=1, bg="white",
                                text="? ? ?", relief=RAISED)
                    self.lbl.grid(column=c, row=r, padx=1, pady=1, sticky=NSEW)
                elif c == 0 and r != 0:
                    self.lbl = Label(self, width=6, height=1, bg="white", 
                                text=f"R{r}",relief=RAISED)
                    self.lbl.grid(column=c, row=r, padx=1, pady=1, sticky=NSEW)
                elif c != 0 and r == 0:
                    self.lbl = Label(self, width=6, height=1, bg="white",
                                text=f"C{c}",relief=RAISED)
                    self.lbl.grid(column=c, row=r, padx=1, pady=1, sticky=NSEW)
                else:
                    self.txt =Text(self, width=6, height=1, bg="white",
                               relief=SUNKEN)
                    self.txt.grid(column=c, row=r, padx=1, pady=1, sticky=NSEW)
        for c in range(self.cols):
            self.grid_columnconfigure(c, weight=1)
                for r in range(self.rows):
                    self.grid_rowconfigure(r, weight=1)

if __name__ == '__main__':
    cols = int(input("How many columns? "))
    assert isinstance(int(cols), int), "integers only, please"
    rows = int(input("How many rows? "))
    assert isinstance(int(rows), int), "integers only, please"
    root = Tk()
    root.geometry("+10+10")
    root.title("Master Table")
    root.grid_columnconfigure(0, weight=1)
    root.grid_rowconfigure(0, weight=1)
    my_table = Calc_Table(root, cols, rows)
    my_table.grid(column=0, row=0, sticky=NSEW)
    my_table.grid_columnconfigure(0, weight=1)
    my_table.grid_rowconfigure(0, weight=1) 
    root.mainloop()

请在下面找到代码,已修改,但画布内的框架和小部件仍然无法展开:

from tkinter import *
class Calc_Table(Frame):
    def __init__(self, root, cols, rows):
        Frame.__init__(self, master=root)
        self.cols = cols
        self.rows = rows
        hscrollbar = Scrollbar(orient=HORIZONTAL)
        hscrollbar.grid(row = 1, column = 0, sticky = EW)
        vscrollbar = Scrollbar(orient=VERTICAL)
        vscrollbar.grid(row = 0, column = 1, sticky = NS)
        self.canvas = Canvas(self, xscrollcommand = hscrollbar.set,      yscrollcommand = vscrollbar.set, bg='yellow')
        self.canvas.grid(row = 0, column = 0, sticky = NSEW)
        self.canvas.grid_rowconfigure(0, weight = 1)
        self.canvas.grid_columnconfigure(0, weight = 1)
        hscrollbar.config(command = self.canvas.xview)
        vscrollbar.config(command = self.canvas.yview)

        self.table_frame = self.create_table(self.cols,self.rows)
        self.canvas_frame = self.canvas.create_window(0, 0, window = self.table_frame, anchor=NW)
        self.canvas.update_idletasks()
        self.canvas.config(scrollregion = self.canvas.bbox('all'))
        print(self.canvas.find_all())          #check canvas slaves
        print(len(self.table_frame.grid_slaves()))   #check table_frame slaves

    def create_table(self, cols, rows):     # build initial table ---->
        self.table_frame = Frame(self.canvas)
        self.table_frame.grid(column = 0, row = 0, sticky = NSEW)
        self.cols, self.rows = cols, rows
        for c in range(self.cols):
            for r in range(self.rows):
                if c == 0 and r == 0:
                    self.lbl = Label(self.table_frame, width=6, height=1, bg="white",text="? ? ?", relief=RAISED)
                    self.lbl.grid(column=c, row=r, padx=1, pady=1,sticky=NSEW)
                elif c == 0 and r != 0:
                    self.lbl = Label(self.table_frame, width=6, height=1, bg="white", text=f"R{r}",relief=RAISED)
                    self.lbl.grid(column=c, row=r, padx=1, pady=1,sticky=NSEW)
                elif c != 0 and r == 0:
                    self.lbl = Label(self.table_frame, width=6, height=1, bg="white",text=f"C{c}",relief=RAISED)
                    self.lbl.grid(column=c, row=r, padx=1, pady=1,sticky=NSEW)
                else:
                    self.txt =Text(self.table_frame, width=6, height=1, bg="white", relief=SUNKEN)
                    self.txt.grid(column=c, row=r, padx=1, pady=1,sticky=NSEW)
        self.table_frame.grid_columnconfigure(0, weight=1)
        self.table_frame.grid_rowconfigure(0, weight=1)
        for c in range(self.cols):
              self.table_frame.grid_columnconfigure(c, weight=1)
            for r in range(self.rows):
              self.table_frame.grid_rowconfigure(r, weight=1)  # end table
        return self.table_frame

if __name__ == '__main__':
    cols = int(input("How many columns? "))
    assert isinstance(int(cols), int), "integers only, please"
    rows = int(input("How many rows? "))
    assert isinstance(int(rows), int), "integers only, please"
    root = Tk()
    root.geometry("+10+10")
    root.title("Master Table")
    root.grid_columnconfigure(0, weight=1)
    root.grid_rowconfigure(0, weight=1)
    my_table = Calc_Table(root, cols, rows)
    my_table.configure(bg = "green")
    my_table.grid(column=0, row=0, sticky=NSEW)
    my_table.grid_columnconfigure(0, weight=1)
    my_table.grid_rowconfigure(0, weight=1) 
    root.mainloop()

【问题讨论】:

  • 一些缩进是你的代码是正确的。 for r in range(self.rows) 应该处于什么级别?

标签: tkinter scrollbar python-3.7 tkinter-canvas


【解决方案1】:

为什么最左边的小部件占用这么大的空间

主要原因是因为画布在self的第0行零列,并且画布的默认大小约为200像素。如果你改变画布的高度,你会看到行的大小改变了相同的量。

另一个问题是,您在create_table 中创建的所有小部件都被指定为self 作为主人。如果您正在尝试创建一个可滚动的表格,那么这些表格必须是画布内框架的子级。

为什么应用会占用所有可用的屏幕空间,甚至缩短小部件,从而不显示滚动滑块。

出于与以前相同的原因 - create_table 将小部件放在根窗口中,并将它们放在与滚动条相同的行和列中。


您做错的根本原因是您没有在画布内创建框架。您需要在create_table 中创建一个框架,将create_table 中的所有其他小部件放在此框架内,然后确保create_table 返回此框架。

def create_table(self, cols, rows):
    table_frame = Frame(self.canvas)
    ...
            self.lbl = Label(table_frame, ...)
    ...
    return table_frame

【讨论】:

  • 我按照您的建议更改了代码;不出所料,它确实奏效了。不幸的是,为了获得滚动,一个失去了扩展:画布内的框架及其子框架不会扩展,即使我在适用的地方喷洒了 grid_columnconfigure 和 grid_rowconfigure 。感谢您的支持。
  • @user2328909:框架应该扩展或收缩以适应其内容,除非您正在采取措施防止这种情况发生。但是,您正在明确设置内部框架的大小,因此它不能增长或缩小。
  • 我确实删除了大小参数,但结果是一样的。还编辑了第一篇文章,以添加修改后的代码。
  • 我挖得更深一点,发现需要一个画布 itemconfig 来使内部框架大小与画布大小保持同步。任务完成。感谢您提供宝贵的帮助。
猜你喜欢
  • 2015-04-18
  • 1970-01-01
  • 2021-10-27
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
相关资源
最近更新 更多