Mon objectif est d’ajouter une barre de défilement verticale à un cadre comportant plusieurs étiquettes. La barre de défilement doit automatiquement être activée dès que les étiquettes à l'intérieur du cadre dépassent sa hauteur. Après avoir cherché, j'ai trouvé this post utile. Sur la base de ce post, je comprends que pour réaliser ce que je veux, (corrigez-moi si je me trompe, je suis débutant), je dois d'abord créer un Frame
, puis créer un Canvas
à l'intérieur de ce cadre et collez la barre de défilement sur ce cadre également. Après cela, créez un autre cadre et placez-le à l'intérieur de la toile en tant qu'objet window. Donc, je viens enfin avec ceci:
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()
anchor='nw'
lors de la création d'une fenêtre sur une toile?Veuillez garder votre réponse simple, car je suis un débutant.
Est-ce que je fais bien les choses? Existe-t-il un moyen meilleur/plus intelligent d'obtenir le résultat obtenu par ce code?
De manière générale, oui, vous le faites bien. Tkinter n'a pas d'autre conteneur natif que le canevas. Comme vous pouvez le constater, ce n’est vraiment pas si difficile à mettre en place. Comme votre exemple le montre, 5 à 6 lignes de code suffisent pour le faire fonctionner, en fonction du nombre de lignes.
Pourquoi dois-je utiliser la méthode grid? (J'ai essayé la méthode place, mais aucune des étiquettes n'apparaît sur le canevas?)
Vous demandez pourquoi vous devez utiliser la grille. Il n'y a aucune obligation d'utiliser la grille. Le lieu, la grille et le sac peuvent tous être utilisés. C'est simplement que certains sont plus naturellement adaptés à des types de problèmes particuliers. Dans ce cas, il semble que vous créiez une grille réelle - des rangées et des colonnes d'étiquettes - le choix de la grille est donc naturel.
Quelle est la particularité d'utiliser anchor = 'nw' lors de la création d'une fenêtre sur une toile?
L'ancre vous indique quelle partie de la fenêtre est positionnée aux coordonnées que vous donnez. Par défaut, le centre de la fenêtre sera placé à la coordonnée. Dans le cas de votre code ci-dessus, vous souhaitez que le coin supérieur gauche ("nord-ouest") se trouve à la coordonnée.
Veuillez noter que le code proposé est uniquement valide avec Python 2
Voici un exemple:
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 __== "__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()
La molette de la souris n’est pas encore reliée à la barre de défilement, mais c’est possible. Faire défiler avec la molette peut cependant devenir un peu cahoteux.
modifier:
à 1)
Le défilement IMHO des cadres est un peu délicat dans Tkinter et ne semble pas être fait beaucoup. Il semble qu'il n'y ait pas de moyen élégant de le faire.
Un problème avec votre code est que vous devez définir la taille de la toile manuellement - c'est ce que l'exemple de code que j'ai posté résout.
à 2)
Vous parlez de la fonction data? Place travaille pour moi aussi. (En général je préfère la grille).
à 3)
Eh bien, il positionne la fenêtre sur la toile.
Une chose que j'ai remarquée est que votre exemple gère le défilement de la molette de la souris par défaut, contrairement à celui que j'ai posté. Devra regarder cela quelque temps.
S'il vous plaît voir ma classe qui est un cadre défilable. Sa barre de défilement verticale est liée à <Mousewheel>
événement aussi. Donc, tout ce que vous avez à faire est de créer un cadre, de le remplir avec les widgets comme vous le souhaitez, puis de faire de ce cadre un enfant de mon ScrolledWindow.scrollwindow
. N'hésitez pas à demander si quelque chose n'est pas clair.
@ Brayan Oakley a utilisé beaucoup de réponses pour répondre à ces questions
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())
Nous pouvons ajouter une barre de défilement même sans utiliser Canvas. Je l'ai lu dans de nombreux autres articles, nous ne pouvons pas ajouter de barre de défilement verticale dans le cadre directement, etc. etc. Mais après plusieurs expériences, nous avons trouvé un moyen d'ajouter une barre de défilement verticale et horizontale :). Veuillez trouver ci-dessous le code utilisé pour créer une barre de défilement dans treeView et 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)