Auto Scrolling TextView
Append new data and have it automatically scroll down.
Topic: GtkTextView (View All Tutorials)
Keywords: gtktextview gtkscrolledwindow autoscroll bottom
Updated: 362 Days Ago, 2007/12/06 10:53
This widget is not a true GtkTextView, you might recognize it as a modified version of the Scrollable Text View tutorial. However since we need scrolling capabilities, that is a good widget to extend.
Hard to tell by a screenshot... trust me and/or download it. Link at bottom.
To automatically scroll, all we need to do is manually rescroll the textview every time we add data to the end of the text buffer. To make life easy, I will create a new method called append() which will jump to the end of the buffer, append the text, then scroll down.
Auto Scrolling Code
#!/usr/bin/php -c/etc/gtk/php.ini
<?php
define('EXECROOT',dirname(__FILE__));
class bob {
static $fp;
static function readline($text) {
if(self::$fp) {
if(($line = fgets(self::$fp))) {
$text->append($line);
return true;
} else {
fclose(self::$fp);
self::$fp = null;
}
}
return false;
}
static function update_gui() {
while(Gtk::events_pending() || Gdk::events_pending()) {
Gtk::main_iteration_do(true);
}
}
}
class bobTextView extends GtkScrolledWindow {
public $viewer,$buffer;
public function __construct($readonly = true) {
parent::__construct();
$this->viewer = new GtkTextView;
$this->buffer = $this->viewer->get_buffer();
$this->set_policy(Gtk::POLICY_NEVER,Gtk::POLICY_ALWAYS);
$this->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
$this->viewer->set_wrap_mode(Gtk::WRAP_WORD_CHAR);
$this->viewer->set_editable(!$readonly);
$this->viewer->set_cursor_visible(!$readonly);
$this->add($this->viewer);
$this->show_all();
return;
}
// note 1
public function append($text) {
$this->buffer->place_cursor($this->buffer->get_end_iter());
$this->buffer->insert_at_cursor($text);
bob::update_gui();
// note 2
$this->viewer->scroll_to_iter($this->buffer->get_end_iter(),0);
bob::update_gui();
return;
}
}
class bobWindow extends GtkWindow {
public $text;
public function __construct() {
parent::__construct();
$this->text = new bobTextView;
$this->set_position(Gtk::WIN_POS_CENTER);
$this->set_size_request(420,200);
$this->set_title('Auto Scrolling GtkTextView');
$this->set_border_width(6);
$this->connect_simple('delete-event',array($this,'on_quit'));
$this->add($this->text);
$this->show_all();
return;
}
public function on_quit() {
$this->hide();
Gtk::main_quit();
return;
}
}
$w = new bobWindow;
if(file_exists($file = EXECROOT.'/demo-data.txt')) {
bob::$fp = fopen($file,'r');
Gtk::timeout_add(1000,array('bob','readline'),$w->text);
} else {
$w->text->append('What did you do with my demo text file?');
}
Gtk::main();
$w->destroy();
unset($w);
exit(0);
?>
Note 1
Here is our new method which we will use to append data to the end of the text buffer. Notice that it was built onto the parent class of my textview and not the actual buffer itself, however it uses the proper text buffer as it should.
Note 2
Notice both before this and after this I manually force the GUI to update. After adding new text we need to give GTK time to recalculate the height of the text area as well as recount the text area iterators. Then we can safely scroll down and know that it will scroll to the correct place. Then after scrolling I force the GUI update again to make sure it gets applied and the user sees it - in case some time later we are using this in a processing loop.
End Game