Tkinter Scrollbar voor frame

Mijn doel is om een ​​verticale schuifbalk toe te voegen aan een frame dat er verschillende labels in heeft. De schuifbalk moet automatisch ingeschakeld zodra de labels in het frame de hoogte van het frame overschrijden. Na het zoeken door, vond ik dit nuttig na. Op basis van die post begrijp ik dat om te bereiken wat ik wil, (corrigeer me als ik het mis heb, ik ben een beginner) Ik moet een Frameeerst maken, en vervolgens een Canvasin dat frame en stick ook de schuifbalk op dat frame. Maak daarna een ander frame en plaats het in het canvas als een vensterobject. Dus ik kom hier eindelijk mee:

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. doe ik het goed? Is er een betere / slimmere manier om de output te bereiken Deze code gaf me?
  2. Waarom moet ik de rastermethode gebruiken? (Ik heb de plaatsmethode geprobeerd, maar geen van de labels verschijnt op het canvas.)
  3. Wat is er zo speciaal aan het gebruik van anchor='nw'bij het maken van een venster op canvas?

Houd je antwoord simpel, want ik ben een beginner.


Antwoord 1, autoriteit 100%

“Doe ik het goed? Is er een betere/slimmere manier om de output te bereiken die deze code me gaf?”

Over het algemeen gesproken, ja, je doet het goed. Tkinter heeft geen andere native schuifbare container dan het canvas. Zoals je kunt zien, is het echt niet zo moeilijk om in te stellen. Zoals je voorbeeld laat zien, zijn er maar 5 of 6 regels code nodig om het te laten werken — afhankelijk van hoe je regels telt.

“Waarom moet ik de rastermethode gebruiken? (ik heb de plaatsmethode geprobeerd, maar geen van de labels verschijnt op het canvas?)”

Je vraagt waarom je grid moet gebruiken. Het is niet verplicht om grid te gebruiken. Plaats, rooster en pak kunnen allemaal worden gebruikt. Het is gewoon zo dat sommige van nature meer geschikt zijn voor bepaalde soorten problemen. In dit geval lijkt het alsof je een echt raster maakt — rijen en kolommen met labels — dus raster is de natuurlijke keuze.

“Wat is er zo speciaal aan het gebruik van anchor=’nw’ bij het maken van een venster op canvas?”

Het anker vertelt je welk deel van het venster zich bevindt op de door jou opgegeven coördinaten. Standaard wordt het midden van het venster op de coördinaat geplaatst. In het geval van je bovenstaande code, wil je dat de linkerbovenhoek (“noordwest”) op de coördinaat staat.


Antwoord 2, autoriteit 91%

Houd er rekening mee dat de voorgestelde code alleen geldig is met Python 2

Hier is een voorbeeld:

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

Het heeft nog niet het muiswiel gebonden aan de schuifbalk, maar het is mogelijk. Scrollen met het wiel kan echter een beetje hobbelig krijgen.

EDIT:

naar 1)
IMHO-scrollende frames is enigszins lastig in TKIER en lijkt niet veel te worden gedaan. Het lijkt erop dat er geen elegante manier is om het te doen.
Een probleem met uw code is dat u de canvasgrootte handmatig moet instellen – dat is wat de voorbeeldcode die ik oplost oplost.

naar 2)
Heb je het over de gegevensfunctie? Plaats werkt ook voor mij. (In het algemeen geef ik de voorkeur aan raster).

naar 3)
Nou, het positioneert het raam op het canvas.

Eén ding dat ik heb gemerkt, is dat uw voorbeeld handgrepen muiswiel dat standaard scrollen terwijl degene die ik heeft gepost niet. Zal dat enige tijd moeten bekijken.


Antwoord 3, Autoriteit 38%

Bekijk mijn klas die een schuifbaar frame is. De verticale schuifbalk is ook gekoppeld aan de gebeurtenis <Mousewheel>. Dus alles wat je hoeft te doen is een frame te maken, het te vullen met widgets zoals jij dat wilt, en dan dit frame een onderliggend element van mijn ScrolledWindow.scrollwindowte maken. Vraag gerust als er iets niet duidelijk is.

Veel gebruikt van @ Brayan Oakley-antwoorden om deze vragen te sluiten

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

Antwoord 4, autoriteit 9%

We kunnen zelfs zonder Canvas een schuifbalk toevoegen. Ik heb het in veel andere berichten gelezen dat we de verticale schuifbalk niet rechtstreeks in het frame kunnen toevoegen, enz. Maar na veel experimenten te hebben gedaan, hebben we een manier gevonden om zowel een verticale als een horizontale schuifbalk toe te voegen :). Hieronder vindt u de code die wordt gebruikt om een schuifbalk in treeView en frame te maken.

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)

Other episodes