如何自动滚动gtk.scrolledwindow?

23

我有一个treeview-widget放在一个ScrolledWindow中,在运行时填充数据。我希望ScrolledWindow自动滚动到列表的结尾。我通过调整每次向treeview中插入一行时vadjustment的值来“解决”了这个问题,例如:

if new_line_in_row:
   adj = self.scrolled_window.get_vadjustment()
   adj.set_value( adj.upper - adj.page_size )
如果我在交互式的ipython会话中运行代码并自己设置值,一切都按预期工作。
如果我使用默认的Python解释器运行代码,则自动滚动不总是起作用。我调试了代码,问题似乎是调整值具有某种“延迟”,并且只有在一段时间后才会更改。
我的问题是:如何可靠地滚动到ScrolledWindow的最大位置?是否会生成特殊信号供我使用?还是有更好的方法来设置adjustment-value

2
好问题。我很久以前就想知道这个问题的答案了。这个问题源自于这个问题,我甚至为此出了150美元的悬赏,但并没有得到我希望得到的答案。 - ptomato
6个回答

29

扩大搜索半径后,我找到了一个与Ruby相关的答案。由于问题涉及GTK,所以可以用任何语言解决:

连接更改的部件,例如我的情况是treeview,使用gtk.widget的“size-allocate”信号,并将gtk.scrolledwindow值设置为“upper - page_size”。示例:

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 )

链接至ruby-forum.com上的原始帖子:

暗示暗示


6
成员变量似乎已被隐藏。请改用 get_upper() 和 get_page_size() 方法。 - Fookatchu

8

Python Gtk 3 版本:

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

意思是设置一个值,这个值等于滚动条上限减去页面大小。

这在例如 gtk.treeview 中不起作用:adj 的值稍后会更新,因此大多数情况下,最后添加的行将不会出现。 - jcoppens

8

fookatchu的答案可以改进,使得回调函数可以被多个小部件使用:

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

2

对于我来说,没有任何建议的解决方案可行,但是我通过这种方式(使用Go的GTk4绑定)实现了所需的行为:

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

其他解决方案会将滚动窗口(我的包含了一个列表框)向下移动到倒数第二个项目,但不会显示最后一个项目。它的表现让我想到需要增加上限,所以我尝试通过页面大小来增加它,然后将滚动值设置为新的上限。


1
顺便说一句,这对GTK3也适用,谢谢你的回答! - Jayson Reis

2

接受的答案帮助我在gtk-rs中找到了自动滚动到内容末尾的Rust解决方案。

这里有一个Rust片段,可能会对其他人有所帮助:

// 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");

请注意,这不适用于Gtk4,因为size-allocate信号已被删除。 - Herohtar

0

仍需要回调函数(我使用的是textView而不是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 )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接