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()
- ¿Lo estoy haciendo bien? ¿Hay alguna forma mejor / más inteligente de lograr la salida que este código me dio?
- ¿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).
- ¿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.