Python tkinter use canvas to create dynamically window with scroll bar

烂漫一生 提交于 2020-01-30 06:49:05

问题


My objective is to solve the problem of the grid exceeding the window(shown as figure.1)

enter image description here

My program function is creating a grid that number of columns defined by user.

I tried using canvas to solve this problem, but it still doesn't work successfully. It doesn't show the full grid in the canvas.(shown as figure.2) enter image description here

Below is my code, could you please help solve the problems or give me some advice. Thanks a lot.

Code:

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()

回答1:


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

You have to sync, the width of the Canvas with the width of the Frame inside.

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:

  • Your usage of canvas.bbox is useless, because it's the dimension you want to layout this widget.

  • Using a fixed width=200, smaller than fm_grid.width will allways cut the fm_grid content, it's not dynamically either.

      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?

  • You bound fm_grid.bind("<Configure>", therefore the event.widget is fm_grid, the Frame inside.
  • Get the dimensions of the event.widget from there w.winfo_... and build a bbox tuple to set scrollregion.
  • Use width to set canvas.width, to be in sync with the 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)
    

    Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6



来源:https://stackoverflow.com/questions/58166128/python-tkinter-use-canvas-to-create-dynamically-window-with-scroll-bar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!