23

I have a treeview-widget inside a ScrolledWindow, which is populated during runtime. I want the ScrolledWindow to auto-scroll to the end of the list. I "solved" the problem, by adjusting the vadjustment of the ScrolledWindow, everytime a row is inserted into the treeview. e.g:

if new_line_in_row:
   adj = self.scrolled_window.get_vadjustment()
   adj.set_value( adj.upper - adj.page_size )

If i run the code in an interactive ipython session and set the value by myself, everything works as expected.

If i run the code with the default python interpreter, the auto-scroll doesn't work all the time. I debugged the code and the problem seems be, that the adjustment values have some kind of "lag" and are only changed after some period of time.

My question is: how do I scroll, reliably, to maximum position of the ScrolledWindow? is a special signal generated which i can use? or is there a better way to set the adjustment-value?

gpoo
  • 8,408
  • 3
  • 38
  • 53
Fookatchu
  • 7,125
  • 5
  • 28
  • 26
  • 2
    Good question. I have wanted to know this for a _long_ time. It came out of [this question](http://stackoverflow.com/questions/2659026/painting-on-gtkscrolledwindow-or-gtkeventbox), which I even offered a bounty of 150 on but didn't get the answer I hoped. – ptomato Mar 07 '11 at 22:05

6 Answers6

29

After widening my search-radius, i found a ruby-related answer. since the problem is gtk-related, it should be able to be solved in any language like this:

you connect the widget which changes, in my case the treeview, with gtk.widget's 'size-allocate' signal and set the gtk.scrolledwindow value to "upper - page_size". example:

self.treeview.connect('size-allocate', self.treeview_changed)

...

def treeview_changed(self, widget, event, data=None):
    adj = self.scrolled_window.get_vadjustment()
    adj.set_value( adj.upper - adj.page_size )

link to the original post at ruby-forum.com:

hint hint

Fookatchu
  • 7,125
  • 5
  • 28
  • 26
8

Python Gtk 3 version:

adj.set_value(adj.get_upper() - adj.get_page_size())

BlackVegetable
  • 12,594
  • 8
  • 50
  • 82
Federico
  • 722
  • 12
  • 12
  • This does not work in eg. a gtk.treeview: `adj`'s values are updated later, so mostly, the last added row will not appear. – jcoppens Jul 13 '17 at 15:19
8

fookatchu's answer can be improved so that the callback could be used by multiple widgets:

def treeview_changed( self, widget, event, data=None ):
    adj = widget.get_vadjustment()
    adj.set_value( adj.upper - adj.pagesize )
Chuck R
  • 731
  • 1
  • 7
  • 15
2

The accepted answer has helped me figure out a Rust solution in gtk-rs to the auto-scroll to end of content issue.

Here's a Rust snippet that might help others:

// Imports used for reference
use gtk::{TextBuffer, TextView, TextBufferBuilder, ScrolledWindow, ScrolledWindowBuilder};

// The text buffer where the text is appended later
let text_buffer: TextBuffer = TextBufferBuilder::new().build();

// The containing text view that holds the text buffer
let text_view: TextView = TextView::new_with_buffer(&text_buffer);

// The scrolled window container with fixed height/width that holds the text view
let scrolled_window: ScrolledWindow = ScrolledWindowBuilder::new()
        .min_content_height(400)
        .min_content_width(600)
        .child(&text_view)
        .build();

// Have the text view connect to signal "size-allocate"
text_view.connect_size_allocate(clone!(@weak scrolled_window => move |_,_| {
   let adj = scrolled_window.get_vadjustment().unwrap();
   adj.set_value(adj.get_upper() - adj.get_page_size());
}));

// ...
// Later on, fill buffer with some text.
text_buffer.insert(&mut text_buffer.get_end_iter(), "This is my text I'm adding");
ddubson
  • 94
  • 1
  • 4
2

None of the suggested solutions worked for me, but I was able to get the desired behavior doing this (using GTk4 bindings for Go):

adj := scrolledWindow.VAdjustment()
adj.SetUpper(adj.Upper() + adj.PageSize())
adj.SetValue(adj.Upper())

The other solutions would move the scrolled window (mine contained a list box) down to the 2nd-to-last item, but not show the last item. The way it was acting made me think that the upper limit needed to be increased, so I tried increasing it by page-size then setting the scroll value to the new upper limit.

Benny Jobigan
  • 5,078
  • 2
  • 31
  • 41
0

Still need the callback (I used a textView rather than treeView):

textView = Gtk.TextView()
scrolledWindow = Gtk.ScrolledWindow()

def textViewChanged( self, widget ):
    adjustment = scrolledWindow.get_vadjustment()
    adjustment.set_value( adjustment.get_upper() - adjustment.get_page_size() )

textView.connect( "size-allocate", textViewChanged )
Bernmeister
  • 267
  • 9
  • 17