Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Scroll a ScrolledText automatically to the end if the user is not scrolling manually

I made my ScrolledText scroll automatically to the end, based on this answer.

Now I'd like to scroll automatically only if the user is not scrolling manually.

I was looking for something like this: self.text.offsetBottom (see my comment in the code below), but couldn't find it yet.

Any ideas? Thanks!

import time
from Tkinter import *
import ScrolledText

class Example(Frame):
    def __init__(self, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)

        self.text = ScrolledText.ScrolledText(self, height=6, width=40)
        self.text.pack(side="left", fill="both", expand=True)
        self.add_timestamp()

    def add_timestamp(self):
        self.text.insert("end", time.ctime() + "\n")

        """ -----> HERE <----- """         
        # if self.text.offsetBottom > 0:
        self.text.see("end")
        self.after(1000, self.add_timestamp)

if __name__ == "__main__":
    root =Tk()
    frame = Example(root)
    frame.pack(fill="both", expand=True)
    root.mainloop()
like image 839
Mr. B. Avatar asked Nov 02 '25 15:11

Mr. B.


1 Answers

You can use the yview() method to see if the widget is fully scrolled down. yview() returns a 2-tuple with the top and bottom of the visible part relative to the total size. So if the widget is fully scrolled down, the second number should be 1.0.

We can use this to only scroll if the widget was fully scrolled down before the insert happened:

def add_timestamp(self):
    fully_scrolled_down = self.text.yview()[1] == 1.0
    self.text.insert("end", time.ctime() + "\n")
    if fully_scrolled_down:
        self.text.see("end")
    self.after(1000, self.add_timestamp)

Another option is to check whether the last character is currently visible or not using

visible = self.text.bbox("end-1c")

From effbot, we can read that this method gives a 4-tuple if the character is visible, or None if the character is not visible:

bbox(index)
Calculates the bounding box for the given character.

This method only works if the text widget is updated. To make sure this is the case, you can call the update_idletasks method first.

index
Character index.
Returns:
A 4-tuple (x, y, width, height), or None, if the character is not visible.

We can use this to only scroll if the last character was visible before the insert happened:

def add_timestamp(self):
    last_char_visible= self.text.bbox("end-1c")
    self.text.insert("end", time.ctime() + "\n")
    if last_char_visible:
        self.text.see("end")
    self.after(1000, self.add_timestamp)
like image 177
fhdrsdg Avatar answered Nov 04 '25 19:11

fhdrsdg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!