in reply to Unable To Keep Showing Last Item In Gtk2::TreeView

Hi, that was a tricky one, and had me scratching my head for a bit. :-)

First, I don't know how the line

$win=new Gtk2::MainWindow();
ran for you. It should be
$win= Gtk2::Window->new();
that was easy. :-) But now to the hard problem.

I got a clue from how the TextView scrolled to end by needing a signal connect on it's underlying buffer, which without it, would exhibit the exact same symptoms of the scroll-to-end going off target after the is window resized smaller. So here is a working version of your script, notice the $model->signal_connect( 'row-inserted' => sub{}).

#!/usr/bin/perl use strict; use warnings; use Glib qw(TRUE FALSE); use Gtk2 -init; my($win,$tree)=createWin(); Glib::Timeout->add(1000,sub {tickCB($tree)}); $win->show_all(); Gtk2->main(); # # Creates the widgets in the application. Returns the main # window and tree view. # my $model; sub createWin { my($win,$scroll,$tree); #,$model); #$win=new Gtk2::MainWindow(); $win = Gtk2::Window->new (); $win->set_default_size(250,300); $win->signal_connect(destroy => \&Gtk2::main_quit); $win->add($scroll=new Gtk2::ScrolledWindow()); $scroll->add($tree=new Gtk2::TreeView()); $tree->set_rules_hint(TRUE); $tree->insert_column_with_attributes(-1,'Goo', new Gtk2::CellRendererText(),text => 0); $tree->set_model($model= new Gtk2::ListStore('Glib::String')); # without this signal connect, making the window bigger # will be ok for scrolling, but will screw up # on making window smaller $model->signal_connect( 'row-inserted' => sub { my ( $view, $iter, $path ) = @_; # print "@_\n"; my($numRows)=$tree->get_model()->iter_n_children(undef); $tree->scroll_to_cell( new Gtk2::TreePath($numRows-1),undef,TRUE,0.0,1.0); } ); addWord($model) for 0 .. 100; showLast($tree); return ($win,$tree); } # # Called at regular intervals to add another random "word" # to the bottom of the tree view. If the previous word was # visible beforehand, scrolls the tree view so the new word # is visible. # sub tickCB { my($tree)=@_; my($model)=$tree->get_model(); my($numRows)=$model->iter_n_children(undef); my($lastVis)=($tree->get_visible_range())[1]; my($mustScroll)=$lastVis && $lastVis->get_indices() == $numRows-1; addWord($model); showLast($tree) if $mustScroll; return TRUE; } # # Adds a random "word" to the bottom of the tree view. # sub addWord { my($model)=@_; my(@cons)=grep !/[aeiou]/,'a' .. 'z'; $model->set($model->append(),0, $cons[rand @cons] . 'oo'); } # # Scrolls the tree view so the last row is visible. # sub showLast { my($tree)=@_; my($numRows)=$tree->get_model()->iter_n_children(undef); $tree->scroll_to_cell( new Gtk2::TreePath($numRows-1),undef,TRUE,0.0,1.0); $tree->set( vadjustment => $tree->get_vadjustment ); }

I'm not really a human, but I play one on earth.
Old Perl Programmer Haiku ................... flash japh

Replies are listed 'Best First'.
Re^2: Unable To Keep Showing Last Item In Gtk2::TreeView
by williams (Beadle) on Apr 09, 2012 at 20:17 UTC

    Thanks for the suggestion. And, oops, on the Window/MainWindow thing. See the corrected version below, still with the shrink problem.

    What you suggested is not quite what I'm after, since it unconditionally moves the scroll bar to the bottom of the view anytime a new item is added. I'm trying to move the scroll bar only if it is already at the bottom just before the new item is added. That way, I can be looking around somewhere else with the scroll bar, without it jumping to the bottom everytime another item is added.

    So it's an annoyance issue: I want this auto-scrolling, but not while I'm looking somewhere else in the tree view. What I've got works, except when the tree view shrinks. That causes the scroll bar to move slightly off the bottom, mistakenly turning off auto-scrolling.

    By the way, I've tried attaching to many different signals, but the tree view internals seem too stale for $tree->get_visible_range(), $tree->scroll_to_cell(), or whatever to work.

    Still searching,

    Jim

    #!/usr/bin/perl use strict; use warnings; use Glib qw(TRUE FALSE); use Gtk2 -init; my($win,$tree)=createWin(); Glib::Timeout->add(1000,sub {tickCB($tree)}); $win->show_all(); Gtk2->main(); # # Creates the widgets in the application. Returns the main # window and tree view. # sub createWin { my($win,$scroll,$tree,$model); $win=new Gtk2::Window(); $win->set_default_size(250,300); $win->signal_connect(destroy => \&Gtk2::main_quit); $win->add($scroll=new Gtk2::ScrolledWindow()); $scroll->add($tree=new Gtk2::TreeView()); $tree->set_rules_hint(TRUE); $tree->insert_column_with_attributes(-1,'Goo', new Gtk2::CellRendererText(),text => 0); $tree->set_model($model= new Gtk2::ListStore('Glib::String')); addWord($model) for 0 .. 100; showLast($tree); return ($win,$tree); } # # Called at regular intervals to add another random "word" # to the bottom of the tree view. If the previous word was # visible beforehand, scrolls the tree view so the new word # is visible. # sub tickCB { my($tree)=@_; my($model)=$tree->get_model(); my($numRows)=$model->iter_n_children(undef); my($lastVis)=($tree->get_visible_range())[1]; my($mustScroll)=$lastVis && $lastVis->get_indices() == $numRows-1; addWord($model); showLast($tree) if $mustScroll; return TRUE; } # # Adds a random "word" to the bottom of the tree view. # sub addWord { my($model)=@_; my(@cons)=grep !/[aeiou]/,'a' .. 'z'; $model->set($model->append(),0, $cons[rand @cons] . 'oo'); } # # Scrolls the tree view so the last row is visible. # sub showLast { my($tree)=@_; my($numRows)=$tree->get_model()->iter_n_children(undef); $tree->scroll_to_cell( new Gtk2::TreePath($numRows-1),undef,TRUE,0.0,1.0); }
      Hi again, this is about as far as I got experimenting with maintaining scroll position. This script isn't considered bullet proof, it has a runaway condition if you click too fast on the zoom control, and not all the Labels work as intended. You might get some experience with Adjustments by playing with it. It also is on a Goo canvas, not a TreeView.:-)

      I'm not really a human, but I play one on earth.
      Old Perl Programmer Haiku ................... flash japh

        I posted this question to gtk-perl, and was able to get something that appears to do what I want. To summarize, I found the right signals to watch for to keep the scroll bar at the bottom, unless the user moves it. It reacts correctly when items are added to the tree view, and when the window height shrinks.

        I include my final version below for reference. Thanks for the help.

        Jim

        #!/usr/bin/perl use strict; use warnings; use Glib qw(TRUE FALSE); use Gtk2 -init; my($numAdded)=0; my($win,$tree)=createWin(); Glib::Timeout->add(1000,sub {tickCB($tree)}); $win->show_all(); Gtk2->main(); # # Creates the widgets in the application. Returns the main # window and tree view. # sub createWin { my($win,$scroll,$tree,$model,$mustScroll); $win=new Gtk2::Window(); $win->set_default_size(250,300); $win->signal_connect(destroy => \&Gtk2::main_quit); $win->add($scroll=new Gtk2::ScrolledWindow()); $scroll->add($tree=new Gtk2::TreeView()); $tree->set_rules_hint(TRUE); $tree->insert_column_with_attributes(-1,'Goo', new Gtk2::CellRendererText(),text => 0); $tree->set_model($model= new Gtk2::ListStore('Glib::String')); $tree->signal_connect( size_allocate => sub {sizeCB(\$mustScroll,@_)}); $model->signal_connect( row_inserted => sub {rowCB(\$mustScroll,$tree,@_)}); $scroll->get_vadjustment()->signal_connect( value_changed => sub {$numAdded=0}); addWords($model,100); showLast($tree,\$mustScroll); return ($win,$tree); } # # Called at regular intervals to add more random "words" to # the bottom of the tree view. If the previous word was # visible beforehand, scrolls the tree view so the new # words are visible. # sub tickCB { my($tree)=@_; addWords($tree->get_model(),100); return TRUE; } # # Adds random "words" to the bottom of the tree view. # sub addWords { my($model,$numAdd)=@_; my(@cons)=grep !/[aeiou]/,'a' .. 'z'; for (1 .. $numAdd) { $model->set($model->append(),0, $cons[rand @cons] . 'oo'); $numAdded++; } } # # Scrolls the tree view so the last row is visible. # sub showLast { my($tree,$mustScroll)=@_; my($numRows)=$tree->get_model()->iter_n_children(undef); $tree->scroll_to_cell( new Gtk2::TreePath($numRows-1),undef,TRUE,0.0,1.0); $$mustScroll=TRUE; $numAdded=0; } # # Called each time the tree view is resized. This is where # we correct the scroll bar, moving it to the bottom if # appropriate. # sub sizeCB { my($mustScroll,$tree,$rect)=@_; showLast($tree,$mustScroll) if $$mustScroll; } # # Called each time a row is added to the model. # sub rowCB { my($mustScroll,$tree,$model,$path,$it)=@_; my($numRows)=$model->iter_n_children(undef); my($lastVis); if ($tree->realized()) { $lastVis=($tree->get_visible_range())[1]; $$mustScroll=$lastVis && $lastVis->get_indices() == $numRows-2-$numAdded; } else { $$mustScroll=TRUE; } }