Обзор
Вы можете связать полосы прокрутки только с несколькими виджетами, и корневой виджет и Frame
не являются частью этой группы виджетов.
Наиболее распространенное решение - создать виджет холста и связать полосы прокрутки с этим виджетом.Затем в этот холст вставьте фрейм, содержащий ваши виджеты с ярлыками.Определите ширину / высоту рамки и укажите ее в параметре canvas scrollregion
, чтобы область прокрутки точно соответствовала размеру рамки.
Рисование текстовых элементов непосредственно на холсте не очень сложное,поэтому вы можете пересмотреть этот подход, если решение frame-embedded-in-a-canvas кажется слишком сложным.Так как вы создаете сетку, координаты каждого текстового элемента будет очень легко вычислить, особенно если каждая строка имеет одинаковую высоту (что, вероятно, если вы используете один шрифт).
Для рисования непосредственно на холсте, просто определите высоту строки шрифта, который вы используете (и для этого есть команды).Тогда каждая координата y равна row*(lineheight+spacing)
.Координата x будет фиксированным числом, основанным на самом широком элементе в каждом столбце.Если вы дадите всем тег для столбца, в котором он находится, вы можете с помощью одной команды отрегулировать координату x и ширину всех элементов в столбце.
Объектно-ориентированное решение
ВотПример решения Frame-Embedded-In-Canvas с использованием объектно-ориентированного подхода:
import tkinter as tk
class Example(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
self.canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
self.frame = tk.Frame(self.canvas, background="#ffffff")
self.vsb = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.populate()
def populate(self):
'''Put in some fake data'''
for row in range(100):
tk.Label(self.frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(self.frame, text=t).grid(row=row, column=1)
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
if __name__ == "__main__":
root=tk.Tk()
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Процедурное решение
Вот решение, которое не использует объекты:
import tkinter as tk
def populate(frame):
'''Put in some fake data'''
for row in range(100):
tk.Label(frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(frame, text=t).grid(row=row, column=1)
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
root = tk.Tk()
canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
frame = tk.Frame(canvas, background="#ffffff")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4,4), window=frame, anchor="nw")
frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
populate(frame)
root.mainloop()
Примечание: , чтобы сделать это в Python 2.x, используйте Tkinter
вместо tkinter
в операторе импорта