Python tkinter 使用 canvas 动态创建 window 带滚动条

Python tkinter use canvas to create dynamically window with scroll bar

我的objective是解决网格超出window的问题(如图1)

enter image description here

我的程序功能是创建一个由用户定义的列数的网格。

我尝试使用canvas来解决这个问题,但仍然没有成功。 canvas中没有显示完整的网格。(如图2) enter image description here

下面是我的代码,请大家帮忙解决问题或者给我一些建议。 非常感谢。

代码:

import tkinter as tk
import tkinter.messagebox
import tkinter.filedialog

MainWindow = tk.Tk()

MainWindow.title('Helloworld')
MainWindow.geometry('1000x800')

def btn_generate():
    global EntryNamelist
    global Entrycoordinatelist
    global EntryLabellist
    con_num = en_condition_num.get()
    if con_num != '':
        #### Grid Body
        for i in range(1,int(con_num) +1 ):
                lb_name = tk.Label(fm_grid, text="Condition" + str(i) )
                lb_name.grid(row=i, column=0, padx=2, pady=1, ipadx=20, ipady=5)  
                En_name = tk.Entry(fm_grid, bd = 2,width = 10,font=('Ubuntu', 10))
                En_name.grid(row=i, column=1, padx=2, pady=1, ipadx=35, ipady=5) 
                En_coor = tk.Entry(fm_grid, bd = 2,width = 10,font=('Ubuntu', 10))
                En_coor.grid(row=i, column=2, padx=2, pady=1, ipadx=200, ipady=5)

    else:
        tk.messagebox.showerror("Error", "Please input a num of conditions")

fm_main = tk.Frame()
fm3 = tk.Frame(fm_main)
lb_condition = tk.Label(fm3,text = 'Please input the number of condition')
lb_condition.pack(side="left")
en_condition_num = tk.Entry(fm3, bd = 2,width = 5)
en_condition_num.pack()
fm3.pack()

btn_generate = tk.Button(fm_main,text="Generate Grid",command=btn_generate)
btn_generate.pack()
lb_en = tk.Label(fm_main,text = '')
lb_en.pack()

def myfunction(event):
    canvas.configure(scrollregion=canvas.bbox("all"),width=200,height=200)

canvas=tk.Canvas(fm_main)
fm_grid = tk.Frame(canvas)
fm_grid.pack()
myscrollbar=tk.Scrollbar(fm_main,orient="vertical",command=canvas.yview)
canvas.configure(yscrollcommand=myscrollbar.set)
myscrollbar.pack(side="right",fill="y")
canvas.pack(side="left")
canvas.create_window((4,4),window=fm_grid,anchor='nw')
fm_grid.bind("<Configure>",myfunction)
fm_main.pack()
MainWindow.mainloop()

Question: It doesn't show the full grid in the canvas

您必须将 CanvaswidthFramewidth 同步。

Note: fm_grid = tk.Frame(canvas, bg='blue') is shown in 'blue'.


Dont's:
Remove fm_grid.pack(), you layout with: canvas.create_window(....
Also, i recommend not to use a offset (4, 4), because you have to calculate with this offset on every canvas.configure(..., width=width + 4. Use (0, 0) instead.

# fm_grid.pack()
...
canvas.create_window((4,4),window=fm_grid,anchor='nw')

Useless, to create dynamically window:

  • 您对 canvas.bbox 的使用没有用,因为它是您要布置此小部件的维度。

  • 使用固定的width=200,小于fm_grid.width总是剪切 fm_grid的内容,它是也不是动态的

      canvas.configure(scrollregion=canvas.bbox("all"),width=200,height=200)
    

How to sync the width of the Canvas with the width of the Frame inside?

  • 你绑定了fm_grid.bind("<Configure>",所以event.widgetfm_grid,里面的Frame
  • 从那里获取 event.widget 的维度 w.winfo_... 并构建一个 bbox 元组来设置 scrollregion
  • 使用width设置canvas.width,与event.widget.winfo_width()同步。

    class ScrollCanvas(tk.Canvas):
        def __init__(self, parent, **kwargs):
            super().__init__(parent, **kwargs)
    
        def create_window(self, child):
            super().create_window((0, 0), window=child, anchor='nw')
            child.bind("<Configure>", self.on_configure)
    
        def on_configure(self, event):
            w = event.widget        
            bbox = x, y, width, height = 0, 0, w.winfo_width(), w.winfo_height()
            self.configure(scrollregion=bbox, width=width)
    

    测试 Python:3.5 - 'TclVersion':8.6 'TkVersion':8.6