简体   繁体   中英

Jump a Tkinter scrollbar to a certain widget

I have added some scrollbar functionality to my Tkinter GUI like so

self.canvas = tk.Canvas(self.baseframe)
self.scrollbar = tk.Scrollbar(self.baseframe, orient="vertical", command=self.canvas.yview)
self.scrollable = tk.Frame(self.canvas)
self.scrollable.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")))
self.canvas.create_window((0, 0), window=self.scrollable, anchor="n")
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.canvas.bind_all("<MouseWheel>", self._mousescroll)

I have defined _mousecroll() as

    def _mousescroll(self, event):
        """mouse wheel scroll callback"""
        # Divide the event.delta by some value to effect the scrolling speed
        self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")

which is working nicely.

I then add some tkLabelFrame widgets to the scroll area (which themselves contain widgets displaying stuff - not relevant for this question). The whole scrolling functionality works really well.

In other part of my GUI, I would like the user to be able to "jump" to a specific point in the scroll area, on a button click. In effect automatically scroll the scroll area to this point. Is this possible? I have full control over the GUI code so I can add labels to the list of tkLabelFrames, store them in some kind of list/dictionary so they can easily be looked up...something like that?

Note: The number of tkLabelFrames that are added to the scroll area is dynamic so some kind of absolute "jump to this many pixels" would probably not work. I was hoping there might be some kind of "scroll to a widget with this label/attribute etc.." functionality. Any help appreciated. Thanks.

For my particular scenario, the widgets within the scrollable area where all the same height, so I was able to use a simple fraction to scroll to the correct place.

Adding a button, with a callback to a method like this worked for me:

def scrollto(self, idx):
    # Where self.frames is the list of tkLabelFrame objects.
    fraction = float(idx/len(self.frames))

    # self.canvas is my scrollable canvas
    self.canvas.yview_moveto(fraction)

I'm reviving this because its the first result in google and not everyone's widgets will be the same height (as required by the current accepted answer's solution).


Using some .winfo functions, we can do some quick maths to find the widget we want to jump to's exact position within 'self.scrollable'.

NOTE: You may need to call .update() on your tkinter instance before calling the jump function, otherwise the winfo values may be incorrect.


We will use the following:

  • .winfo_height() - Get the height of this widget, in pixels. Will return 1 if the window isn't managed by a geometry manager

  • .winfo_rooty() - Get the pixel coordinates for the widget's upper edge, relative to the screen's upper left corner.

  • .yview_moveto(fraction) - Move view to location. 0 is the top, 1 is the bottom


The following function will jump to the given widget, placing it at the top of the viewable area (self.canvas).

 def jump_to_widget_top(self, widget):
      if self.scrollable.winfo_height() > self.canvas.winfo_height():
           pos = widget.winfo_rooty() - self.scrollable.winfo_rooty()
           height = self.scrollable.winfo_height()
           self.canvas.yview_moveto(pos / height)

First we check that the container(self.scrollable) is actually larger than the viewing area. No need to jump if everything is already displayed.

We find the absolute position of the desired widget (relative to the screen), then subtract the distance from the top of the container(self.scrollable) to the top of the screen. This gives us the widgets position relative to the position of the container.

With the widget's position found, dividing it by the height of the container(self.scrollable) we get the fractional location of the widget, as required by .yview_moveto().


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM