desplazamiento barra python tkinter scrollbar frame

barra - python tkinter label frame



Barra de desplazamiento de Python Tkinter para el marco (4)

Mi objetivo es agregar una barra de desplazamiento vertical a un marco que tiene varias etiquetas. La barra de desplazamiento debería habilitarse automáticamente tan pronto como las etiquetas dentro del marco excedan la altura del marco. Después de buscar, encontré this publicación útil. Basado en esa publicación, entiendo que para lograr lo que quiero (corrígeme si estoy equivocado, soy un principiante) primero tengo que crear un Marco, luego crear un Lienzo dentro de ese marco y pegar la barra de desplazamiento a ese marco también. Después de eso, crea otro marco y ponlo dentro del lienzo como un objeto de ventana. Entonces, finalmente se me ocurrió 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("<Configure>",myfunction) data() root.mainloop()

  1. ¿Lo estoy haciendo bien? ¿Hay alguna forma mejor / más inteligente de lograr la salida que este código me dio?
  2. ¿Por qué debo usar el método de cuadrícula? (Probé el método de lugar, pero ninguna de las etiquetas aparece en el lienzo).
  3. ¿Qué tiene de especial el uso de anchor = ''nw'' al crear una ventana en el lienzo?

Por favor, mantenga su respuesta simple ya que soy un principiante. Gracias por tu ayuda.


Podemos agregar barra de desplazamiento incluso sin utilizar Canvas. Lo he leído en muchas otras publicaciones, no podemos agregar una barra de desplazamiento vertical en el marco directamente, etc., etc. Pero después de hacer muchos experimentos descubrimos la forma de agregar barra de desplazamiento vertical y horizontal :). Por favor encuentre el código a continuación que se usa 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)


Por favor, mira mi clase que es un marco desplazable. Su barra de desplazamiento vertical está <Mousewheel> evento <Mousewheel> también. Por lo tanto, todo lo que tienes que hacer es crear un marco, llenarlo con widgets de la manera que quieras y luego convertir este marco en un elemento secundario de mi ScrolledWindow.scrollwindow . No dude en preguntar si algo no está claro.

Usó muchas respuestas de @Brayan Oakley para cerrar estas preguntas

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


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

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

editar:

a 1)
Marcos de desplazamiento en mi humilde opinión es algo complicado en Tkinter y parece que no se hace mucho. Parece que no hay una forma elegante de hacerlo.
Un problema con su código es que debe establecer el tamaño del lienzo de forma manual; 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 la cuadrícula).

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

Una cosa que noté es que su ejemplo maneja el desplazamiento de la rueda del mouse por defecto, mientras que el que publiqué no lo hace. Tendrá que ver eso algún tiempo.


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

En términos generales, sí, lo estás haciendo bien. Tkinter no tiene un contenedor nativo desplazable que no sea el lienzo. 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 lugar, pero ninguna de las etiquetas aparece en el lienzo?)

Usted pregunta por qué debe usar la cuadrícula. No hay ningún requisito para usar la grilla. Lugar, cuadrícula y paquete se pueden utilizar todos. 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 etiquetas), 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 el lienzo?

El ancla te dice qué parte de la ventana está ubicada 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.