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()
  1. 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é?
  2. 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.)
  3. 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.

37
demandé sur Community 2013-04-24 13:32:05

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.

15
répondu Bryan Oakley 2013-05-30 17:05:23

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.

33
répondu Gonzo 2018-02-06 21:51:25

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())
9
répondu Mikhail T. 2016-07-25 06:21:16

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)
2
répondu Aditi Raghuvanshi 2017-07-26 02:46:17