Python Tkinter barre de défilement pour l'image
Mon objectif est d'ajouter une barre de défilement verticale pour un cadre qui a plusieurs étiquettes. La barre de défilement devrait être activée automatiquement dès que les étiquettes à l'intérieur du cadre dépassent la hauteur du cadre. Après avoir cherché, j'ai trouvé ce post utile. Sur la base de ce post je comprends que pour atteindre ce que je veux, (corriger moi si je me trompe, je suis un débutant) je dois créer un cadre d'abord, puis créer une toile à l'intérieur de ce cadre et coller le barre de défilement de l'image. Après cela, créer un autre cadre et le mettre à l'intérieur de la toile comme un objet de fenêtre. Donc, j'ai finalement trouvé ce
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()
- est-ce que je le fais bien? Y a-t-il une meilleure façon/plus intelligente d'atteindre le résultat que ce code m'a donné?
- Pourquoi dois-je utiliser la méthode de la grille? (J'ai essayé la méthode du lieu, mais aucune des étiquettes n'apparaît sur la toile.)
- Qu'est-ce que l'utilisation d'anchor= 'nw' lors de la création fenêtre sur la toile?
s'il vous Plaît garder votre réponse simple comme je suis un débutant. Merci pour votre aide.
4 réponses
est-ce que je le fais bien?Y a-t-il une meilleure façon/plus intelligente d'atteindre le résultat que ce code m'a donné?
en général, oui, vous le faites bien. Tkinter n'a pas de contenant natif scrollable autre que la toile. Comme vous pouvez le voir, ce n'est pas si difficile à mettre en place. Comme votre exemple le montre, il suffit de 5 ou 6 lignes de code pour que cela fonctionne -- selon la façon dont vous comptez les lignes.
Pourquoi dois-je utiliser grille de méthode?(j'ai essayé la méthode du lieu, mais aucune des étiquettes n'apparaît sur la toile?)
vous demandez pourquoi vous devez utiliser grid. Il n'est pas nécessaire d'utiliser la grille. Place, grille et pack peuvent tous être utilisés. Il est tout simplement que certains sont plus naturellement adaptés à des types particuliers de problèmes. Dans ce cas, il semble que vous créez une grille réelle -- des lignes et des colonnes d'étiquettes -- donc la grille est le choix naturel.
Quoi de si spécial utiliser anchor= 'nw' lors de la création de window on canvas?
L'ancre vous indique quelle partie de la fenêtre est positionné aux coordonnées que vous donnez. Par défaut, le centre de la fenêtre sera placé à la coordonner. Dans le cas de votre code ci-dessus, vous voulez que le coin supérieur gauche ("nord-ouest") soit à la coordonnée.
veuillez noter que le code proposé n'est valide qu'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 __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()
il n'a pas encore la roue de la souris liée à la barre de défilement, mais il est possible. Défiler avec la roue peut devenir un peu bosselé, cependant.
edit:
à 1)
IMHO scrolling frames est un peu délicat dans Tkinter et ne semble pas être fait beaucoup. Il semble qu'il n'y ait pas de façon élégante 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 le code d'exemple que j'ai posté résout.
à 2)
Vous parlez de la fonction de données? Place fonctionne pour moi, trop. (En général je préfère la grille).
à 3)
Il place la fenêtre sur la toile.
une chose que j'ai remarqué est que votre exemple gère le défilement de la roue de la souris par défaut alors que celui que j'ai posté ne le fait pas. Aurez à regarder qu'à un certain moment.
s'il vous Plaît voir ma classe qui est un cadre défilant. Son scrollbar vertical est aussi lié à l'événement <Mousewheel>
. Donc, tout ce que vous avez à faire est de créer un cadre, le remplir avec des widgets comme vous voulez, et puis faire de ce cadre un enfant de mon ScrolledWindow.scrollwindow
. N'hésitez pas à demander si quelque chose n'est pas claire.
utilisé beaucoup de @ Brayan Oakley réponses à proximité de 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 la barre de défilement même sans utiliser la toile. Je l'ai lu dans beaucoup d'autres post nous ne pouvons pas ajouter la barre de défilement vertical dans le cadre directement etc etc Mais après avoir fait de nombreuses expériences trouvé moyen d'ajouter verticale ainsi que la barre de défilement horizontale:). Veuillez trouver ci-dessous le code qui est utilisé pour créer la 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)