Python tkinter использует холст для динамического создания окна с полосой прокрутки

Моя цель - решить проблему выхода сетки за окно (показано на рисунке 1).

введите описание изображения здесь

Моя программная функция создает сетку, в которой количество столбцов определяется пользователем.

Я попытался использовать холст для решения этой проблемы, но он все равно не работает. Он не показывает всю сетку на холсте.(Показано на рисунке 2) введите описание изображения здесь

Ниже мой код, не могли бы вы помочь решить проблемы или дать мне совет. Большое спасибо.

Код:

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 ответ

Решение

Вопрос: не отображается вся сетка на холсте

Вы должны синхронизировать width из Canvas с width из Frame внутри.

Примечание:fm_grid = tk.Frame(canvas, bg='blue') показано в 'blue'.


Нельзя:
удалитьfm_grid.pack(), ваш макет с: canvas.create_window(....
Также я рекомендую не использовать смещение(4, 4), потому что вы должны рассчитывать это смещение на каждом canvas.configure(..., width=width + 4. Использовать(0, 0)вместо этого.

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

Бесполезно, чтобы динамически создавать окно:

  • Ваше использование canvas.bbox бесполезен, потому что это размер, в котором вы хотите разместить этот виджет.

  • Используя фиксированный width=200, меньше чем fm_grid.widthбудет ВСЕГДА вырезатьfm_gridконтент, это тоже не динамически.

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

Как синхронизировать width из Canvas с width из Frame внутри?

  • Вы связаны fm_grid.bind("<Configure>", Следовательно event.widget является fm_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

Другие вопросы по тегам