Полоса прокрутки Python Tkinter для кадра
моя цель-добавить вертикальную полосу прокрутки к кадру, в котором есть несколько меток. Полоса прокрутки должна автоматически включаться, как только метки внутри рамки превысят высоту рамки. После поиска, я нашел этой полезное сообщение. Основываясь на этом посте, я понимаю, что для достижения того, что я хочу (исправьте меня, если я ошибаюсь, Я новичок), я должен сначала создать кадр, затем создать холст внутри этого кадра и вставить полосу прокрутки в и эта рамка тоже. После этого создайте еще один кадр и поместите его внутри холста в качестве объекта окна. Итак, я, наконец, придумал это
from Tkinter import *
def data():
for i in range(50):
Label(frame,text=i).grid(row=i,column=0)
Label(frame,text="my text"+str(i)).grid(row=i,column=1)
Label(frame,text="..........").grid(row=i,column=2)
def myfunction(event):
canvas.configure(scrollregion=canvas.bbox("all"),width=200,height=200)
root=Tk()
sizex = 800
sizey = 600
posx = 100
posy = 100
root.wm_geometry("%dx%d+%d+%d" % (sizex, sizey, posx, posy))
myframe=Frame(root,relief=GROOVE,width=50,height=100,bd=1)
myframe.place(x=10,y=10)
canvas=Canvas(myframe)
frame=Frame(canvas)
myscrollbar=Scrollbar(myframe,orient="vertical",command=canvas.yview)
canvas.configure(yscrollcommand=myscrollbar.set)
myscrollbar.pack(side="right",fill="y")
canvas.pack(side="left")
canvas.create_window((0,0),window=frame,anchor='nw')
frame.bind("<Configure>",myfunction)
data()
root.mainloop()
- правильно ли я это делаю? Есть ли лучший / более умный способ достичь результата, который дал мне этот код?
- почему я должен использовать метод сетки? (Я попробовал метод place, но ни одна из меток не появляется на холсте.)
- что такого особенного в использовании anchor= ' nw ' при создании окна на холсте?
Пожалуйста, продолжайте ваш ответ прост, как я новичок. Спасибо за помощь.
4 ответов
Я делаю это правильно?Есть ли лучший / более умный способ достичь результата, который дал мне этот код?
вообще говоря, да, вы все делаете правильно. У Tkinter нет собственного прокручиваемого контейнера, кроме canvas. Как вы можете видеть, это действительно не так сложно настроить. Как показывает ваш пример, для его работы требуется всего 5 или 6 строк кода - в зависимости от того, как вы считаете строки.
почему я должен использовать метод grid?(я пробовал метод, но ни одна из меток не появляется на холсте?)
вы спрашиваете, почему вы должны использовать grid. Нет необходимости использовать grid. Место, решетку и пакет можно все использовать. Просто некоторые из них более естественно подходят для определенных типов проблем. В этом случае похоже, что вы создаете фактическую сетку-строки и столбцы меток-поэтому сетка является естественным выбором.
что такого особенного в использовании anchor= 'nw' при создании окна на холст?
якорь сообщает вам, какая часть окна расположена в заданных вами координатах. По умолчанию центр окна будет располагаться по координате. В случае вашего кода выше вы хотите, чтобы верхний левый ("северо-западный") угол был в координате.
обратите внимание, что предлагаемый код действителен только с Python 2
вот пример:
from Tkinter import * # from x import * is bad practice
from ttk import *
# http://tkinter.unpythonic.net/wiki/VerticalScrolledFrame
class VerticalScrolledFrame(Frame):
"""A pure Tkinter scrollable frame that actually works!
* Use the 'interior' attribute to place widgets inside the scrollable frame
* Construct and pack/place/grid normally
* This frame only allows vertical scrolling
"""
def __init__(self, parent, *args, **kw):
Frame.__init__(self, parent, *args, **kw)
# create a canvas object and a vertical scrollbar for scrolling it
vscrollbar = Scrollbar(self, orient=VERTICAL)
vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
canvas = Canvas(self, bd=0, highlightthickness=0,
yscrollcommand=vscrollbar.set)
canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
vscrollbar.config(command=canvas.yview)
# reset the view
canvas.xview_moveto(0)
canvas.yview_moveto(0)
# create a frame inside the canvas which will be scrolled with it
self.interior = interior = Frame(canvas)
interior_id = canvas.create_window(0, 0, window=interior,
anchor=NW)
# track changes to the canvas and frame width and sync them,
# also updating the scrollbar
def _configure_interior(event):
# update the scrollbars to match the size of the inner frame
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the canvas's width to fit the inner frame
canvas.config(width=interior.winfo_reqwidth())
interior.bind('<Configure>', _configure_interior)
def _configure_canvas(event):
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the inner frame's width to fill the canvas
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
canvas.bind('<Configure>', _configure_canvas)
if __name__ == "__main__":
class SampleApp(Tk):
def __init__(self, *args, **kwargs):
root = Tk.__init__(self, *args, **kwargs)
self.frame = VerticalScrolledFrame(root)
self.frame.pack()
self.label = Label(text="Shrink the window to activate the scrollbar.")
self.label.pack()
buttons = []
for i in range(10):
buttons.append(Button(self.frame.interior, text="Button " + str(i)))
buttons[-1].pack()
app = SampleApp()
app.mainloop()
у него еще нет колеса мыши, привязанного к полосе прокрутки, но это возможно. Прокрутка с колесом может стать немного ухабистой.
изменить:
к 1)
IMHO прокрутки кадров несколько сложно в Tkinter и, похоже, не так много. Кажется, нет элегантного способа сделать это.
Одна проблема с ваш код заключается в том, что вы должны установить размер холста вручную - это то, что решает пример кода, который я опубликовал.
в 2)
Вы говорите о функции данных? Мне тоже подходит это место. (Вообще я предпочитаю grid).
в 3)
Ну, он позиционирует окно на холсте.
Я заметил, что ваш пример обрабатывает прокрутку колесика мыши по умолчанию, а тот, который я опубликовал, - нет. Придется на это посмотреть.
пожалуйста, посмотрите мой класс, который является прокручиваемым кадром. Это вертикальная полоса прокрутки привязана к <Mousewheel>
мероприятие. Итак, все, что вам нужно сделать, это создать кадр, заполнить его виджетами так, как вам нравится, а затем сделать этот кадр ребенком my ScrolledWindow.scrollwindow
. Не стесняйтесь спрашивать, если что-то неясно.
используется много из ответов @ Brayan Oakley, чтобы закрыть эти вопросы
class ScrolledWindow(tk.Frame):
"""
1. Master widget gets scrollbars and a canvas. Scrollbars are connected
to canvas scrollregion.
2. self.scrollwindow is created and inserted into canvas
Usage Guideline:
Assign any widgets as children of <ScrolledWindow instance>.scrollwindow
to get them inserted into canvas
__init__(self, parent, canv_w = 400, canv_h = 400, *args, **kwargs)
docstring:
Parent = master of scrolled window
canv_w - width of canvas
canv_h - height of canvas
"""
def __init__(self, parent, canv_w = 400, canv_h = 400, *args, **kwargs):
"""Parent = master of scrolled window
canv_w - width of canvas
canv_h - height of canvas
"""
super().__init__(parent, *args, **kwargs)
self.parent = parent
# creating a scrollbars
self.xscrlbr = ttk.Scrollbar(self.parent, orient = 'horizontal')
self.xscrlbr.grid(column = 0, row = 1, sticky = 'ew', columnspan = 2)
self.yscrlbr = ttk.Scrollbar(self.parent)
self.yscrlbr.grid(column = 1, row = 0, sticky = 'ns')
# creating a canvas
self.canv = tk.Canvas(self.parent)
self.canv.config(relief = 'flat',
width = 10,
heigh = 10, bd = 2)
# placing a canvas into frame
self.canv.grid(column = 0, row = 0, sticky = 'nsew')
# accociating scrollbar comands to canvas scroling
self.xscrlbr.config(command = self.canv.xview)
self.yscrlbr.config(command = self.canv.yview)
# creating a frame to inserto to canvas
self.scrollwindow = ttk.Frame(self.parent)
self.canv.create_window(0, 0, window = self.scrollwindow, anchor = 'nw')
self.canv.config(xscrollcommand = self.xscrlbr.set,
yscrollcommand = self.yscrlbr.set,
scrollregion = (0, 0, 100, 100))
self.yscrlbr.lift(self.scrollwindow)
self.xscrlbr.lift(self.scrollwindow)
self.scrollwindow.bind('<Configure>', self._configure_window)
self.scrollwindow.bind('<Enter>', self._bound_to_mousewheel)
self.scrollwindow.bind('<Leave>', self._unbound_to_mousewheel)
return
def _bound_to_mousewheel(self, event):
self.canv.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbound_to_mousewheel(self, event):
self.canv.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event):
self.canv.yview_scroll(int(-1*(event.delta/120)), "units")
def _configure_window(self, event):
# update the scrollbars to match the size of the inner frame
size = (self.scrollwindow.winfo_reqwidth(), self.scrollwindow.winfo_reqheight())
self.canv.config(scrollregion='0 0 %s %s' % size)
if self.scrollwindow.winfo_reqwidth() != self.canv.winfo_width():
# update the canvas's width to fit the inner frame
self.canv.config(width = self.scrollwindow.winfo_reqwidth())
if self.scrollwindow.winfo_reqheight() != self.canv.winfo_height():
# update the canvas's width to fit the inner frame
self.canv.config(height = self.scrollwindow.winfo_reqheight())
мы можем добавить полосу прокрутки, даже без использования Canvas. Я прочитал его во многих других сообщениях, мы не можем добавить вертикальную полосу прокрутки в кадре напрямую и т. д. Но после проведения многих экспериментов выяснилось, как добавить вертикальную, а также горизонтальную полосу прокрутки:). Ниже приведен код, который используется для создания полосы прокрутки в treeView и frame.
f = Tkinter.Frame(self.master,width=3)
f.grid(row=2, column=0, columnspan=8, rowspan=10, pady=30, padx=30)
f.config(width=5)
self.tree = ttk.Treeview(f, selectmode="extended")
scbHDirSel =tk.Scrollbar(f, orient=Tkinter.HORIZONTAL, command=self.tree.xview)
scbVDirSel =tk.Scrollbar(f, orient=Tkinter.VERTICAL, command=self.tree.yview)
self.tree.configure(yscrollcommand=scbVDirSel.set, xscrollcommand=scbHDirSel.set)
self.tree["columns"] = (self.columnListOutput)
self.tree.column("#0", width=40)
self.tree.heading("#0", text='SrNo', anchor='w')
self.tree.grid(row=2, column=0, sticky=Tkinter.NSEW,in_=f, columnspan=10, rowspan=10)
scbVDirSel.grid(row=2, column=10, rowspan=10, sticky=Tkinter.NS, in_=f)
scbHDirSel.grid(row=14, column=0, rowspan=2, sticky=Tkinter.EW,in_=f)
f.rowconfigure(0, weight=1)
f.columnconfigure(0, weight=1)