Barra de desplazamiento Tkinter para marco

Mi objective es agregar una barra de desplazamiento vertical a un marco que tenga varias tags. La barra de desplazamiento debería habilitarse automáticamente tan pronto como las tags dentro del marco excedan la altura del marco. Después de buscar a través de, encontré esta publicación útil. Basado en esa publicación, entiendo que para lograr lo que quiero (corríjame si estoy equivocado, soy un principiante) Primero tengo que crear un Frame , luego crear un Canvas dentro de ese marco y pegar la barra de desplazamiento a ese marco también. Después de eso, crea otro marco y colócalo dentro del canvas como un objeto de ventana. Entonces, finalmente se me ocurre esto:

 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("",myfunction) data() root.mainloop() 
  1. ¿Lo estoy haciendo bien? ¿Hay alguna forma mejor / más inteligente de lograr la salida que me dio este código?
  2. ¿Por qué debo usar el método de cuadrícula? (Intenté colocar el método, pero ninguna de las tags aparece en el canvas).
  3. ¿Qué tiene de especial el uso de anchor='nw' al crear una ventana en un canvas?

Por favor, mantenga su respuesta simple, ya que soy un principiante.

¿Lo estoy haciendo bien? ¿Hay alguna forma mejor / más inteligente de lograr la salida que me dio este código?

En general, sí, lo estás haciendo bien. Tkinter no tiene un contenedor desplazable nativo que no sea el canvas. Como puede ver, realmente no es tan difícil de configurar. Como muestra su ejemplo, solo se necesitan 5 o 6 líneas de código para que funcione, dependiendo de cómo cuente las líneas.

¿Por qué debo usar el método de cuadrícula (probé el método de colocar, pero ninguna de las tags aparece en el canvas?)

Preguntas por qué debes usar la cuadrícula. No hay ningún requisito para utilizar la red. Se puede utilizar el lugar, la cuadrícula y el paquete. Es simplemente que algunos se adaptan más naturalmente a tipos particulares de problemas. En este caso, parece que está creando una cuadrícula real – filas y columnas de tags – por lo que la cuadrícula es la elección natural.

¿Qué tiene de especial el uso de anchor = ‘nw’ al crear una ventana en un canvas?

El ancla te dice qué parte de la ventana está posicionada en las coordenadas que das. Por defecto, el centro de la ventana se colocará en la coordenada. En el caso de su código anterior, desea que la esquina superior izquierda (“noroeste”) esté en la coordenada.

Tenga en cuenta que el código propuesto solo es válido con Python 2

Aquí hay un ejemplo:

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

Todavía no tiene la rueda del mouse vinculada a la barra de desplazamiento, pero es posible. Sin embargo, desplazarse con la rueda puede ser un poco irregular.

editar:

a 1)
Los marcos de desplazamiento IMHO son un tanto complicados en Tkinter y parece que no se hacen mucho. Parece que no hay una forma elegante de hacerlo.
Un problema con su código es que tiene que establecer el tamaño del canvas manualmente: eso es lo que resuelve el código de ejemplo que publiqué.

a 2)
¿Estás hablando de la función de datos? El lugar también funciona para mí. (En general prefiero grid).

a 3)
Bueno, coloca la ventana en el canvas.

Una cosa que noté es que su ejemplo controla el desplazamiento de la rueda del mouse por defecto, mientras que el que publiqué no lo hace. Habrá que mirar eso alguna vez.

Por favor, vea mi clase que es un marco desplazable. Su barra de desplazamiento vertical también está evento . Por lo tanto, todo lo que tiene que hacer es crear un marco, llenarlo con los widgets de la forma que desee, y luego hacer de este marco un elemento secundario de mi ScrolledWindow.scrollwindow . Siéntase libre de preguntar si algo no está claro.

Usé mucho las respuestas de @ Brayan Oakley para cerrar esta pregunta

 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 .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('', self._configure_window) self.scrollwindow.bind('', self._bound_to_mousewheel) self.scrollwindow.bind('', self._unbound_to_mousewheel) return def _bound_to_mousewheel(self, event): self.canv.bind_all("", self._on_mousewheel) def _unbound_to_mousewheel(self, event): self.canv.unbind_all("") 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()) 

Podemos añadir barra de desplazamiento incluso sin usar canvas. Lo he leído en muchas otras publicaciones, no podemos agregar la barra de desplazamiento vertical directamente en el marco, etc. Pero, después de hacer muchos experimentos, descubrí la forma de agregar la barra de desplazamiento vertical y horizontal :). A continuación, encontrará el código que se utiliza para crear la barra de desplazamiento en treeView y 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)