文本添加到文本缓冲区时 GTK TextView 自动滚动
GTK TextView auto scroll when text is added to text buffer
我正在尝试创建一个非常简单的类似日志的 GUI 应用程序,它仅动态和异步地显示日志文件中的文本。问题是,当更新日志文件时,GUI 中的文本视图会滚动回第 1 行。每次修复此问题的尝试都失败了,我想知道我是否偶然发现了 GTK 中的错误。这是我的代码摘要:
using Cairo;
using Gtk;
namespace ServerManager {
public class ServerManager : Window {
public TextView text_view;
public TextIter myIter;
public TextMark myMark;
public async void read_something_async (File file) {
var text = new StringBuilder ();
var dis = new DataInputStream (file.read ());
string line;
while ((line = yield dis.read_line_async (Priority.DEFAULT)) != null) {
text.append (line);
text.append_c('\n');
}
this.text_view.buffer.text = text.str;
text_view.buffer.get_end_iter(out myIter);
text_view.scroll_to_iter(myIter, 0, false, 0, 0);
}
public static int main (string[] args) {
Gtk.init (ref args);
var window = new ServerManager ();
// The read-only TextView
window.text_view = new TextView ();
window.text_view.editable = false;
window.text_view.cursor_visible = false;
window.text_view.wrap_mode = Gtk.WrapMode.WORD;
// Add scrolling functionality to the TextView
var scroll = new ScrolledWindow (null, null);
scroll.set_policy (PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
scroll.add (window.text_view);
// Vbox so that our TextView has someplace to live
var vbox = new Box (Orientation.VERTICAL, 0);
vbox.pack_start (scroll, true, true, 0);
window.add (vbox);
window.set_border_width (12);
window.set_position (Gtk.WindowPosition.CENTER);
window.set_default_size (800, 600);
window.destroy.connect (Gtk.main_quit);
window.show_all ();
File file = File.new_for_path ("/home/user/temp.log");
FileMonitor monitor = file.monitor (FileMonitorFlags.NONE, null);
stdout.printf ("Monitoring: %s\n", file.get_path ());
monitor.changed.connect (() => {
window.read_something_async(file);
});
Gtk.main ();
return 0;
}
}
}
我也尝试过使用 TextMarks 而不是 Iters,但这没有任何影响。
滚动到第一行是因为 read_something_async() 删除缓冲区的当前内容然后写入新内容(这就是设置文本 属性 所做的)。也许这就是您想要的,但除非您跟踪滚动位置,否则您将丢失它。
您的 scroll_to_iter() 未按预期工作的原因可能是:
Note that this function uses the currently-computed height of the lines in the text buffer. Line heights are computed in an idle handler; so this function may not have the desired effect if it’s called before the height computations. To avoid oddness, consider using gtk_text_view_scroll_to_mark() which saves a point to be scrolled to after line validation.
使用 "right gravity" TextMark 调用 TextView.ScrollToMark() 应该适合您。
我正在尝试创建一个非常简单的类似日志的 GUI 应用程序,它仅动态和异步地显示日志文件中的文本。问题是,当更新日志文件时,GUI 中的文本视图会滚动回第 1 行。每次修复此问题的尝试都失败了,我想知道我是否偶然发现了 GTK 中的错误。这是我的代码摘要:
using Cairo;
using Gtk;
namespace ServerManager {
public class ServerManager : Window {
public TextView text_view;
public TextIter myIter;
public TextMark myMark;
public async void read_something_async (File file) {
var text = new StringBuilder ();
var dis = new DataInputStream (file.read ());
string line;
while ((line = yield dis.read_line_async (Priority.DEFAULT)) != null) {
text.append (line);
text.append_c('\n');
}
this.text_view.buffer.text = text.str;
text_view.buffer.get_end_iter(out myIter);
text_view.scroll_to_iter(myIter, 0, false, 0, 0);
}
public static int main (string[] args) {
Gtk.init (ref args);
var window = new ServerManager ();
// The read-only TextView
window.text_view = new TextView ();
window.text_view.editable = false;
window.text_view.cursor_visible = false;
window.text_view.wrap_mode = Gtk.WrapMode.WORD;
// Add scrolling functionality to the TextView
var scroll = new ScrolledWindow (null, null);
scroll.set_policy (PolicyType.AUTOMATIC, PolicyType.AUTOMATIC);
scroll.add (window.text_view);
// Vbox so that our TextView has someplace to live
var vbox = new Box (Orientation.VERTICAL, 0);
vbox.pack_start (scroll, true, true, 0);
window.add (vbox);
window.set_border_width (12);
window.set_position (Gtk.WindowPosition.CENTER);
window.set_default_size (800, 600);
window.destroy.connect (Gtk.main_quit);
window.show_all ();
File file = File.new_for_path ("/home/user/temp.log");
FileMonitor monitor = file.monitor (FileMonitorFlags.NONE, null);
stdout.printf ("Monitoring: %s\n", file.get_path ());
monitor.changed.connect (() => {
window.read_something_async(file);
});
Gtk.main ();
return 0;
}
}
}
我也尝试过使用 TextMarks 而不是 Iters,但这没有任何影响。
滚动到第一行是因为 read_something_async() 删除缓冲区的当前内容然后写入新内容(这就是设置文本 属性 所做的)。也许这就是您想要的,但除非您跟踪滚动位置,否则您将丢失它。
您的 scroll_to_iter() 未按预期工作的原因可能是:
Note that this function uses the currently-computed height of the lines in the text buffer. Line heights are computed in an idle handler; so this function may not have the desired effect if it’s called before the height computations. To avoid oddness, consider using gtk_text_view_scroll_to_mark() which saves a point to be scrolled to after line validation.
使用 "right gravity" TextMark 调用 TextView.ScrollToMark() 应该适合您。