0

我需要在 GtkSourceView 中打开文件并滚动到特定的行。作为一种调试器 gui,它需要经常执行此活动(在切换堆栈帧时),没有瞬态伪影 - 内容的可见重新调整和闪烁。目前,我正在使用以下方法:

from gi.repository import GtkSource
class MyClientWindow:
  def __init__(self):
    self.__sourceview = GtkSource.View()
    self.__sourceview.connect('size-allocate', self.__source_resize)
    ...
  def __source_resize(self, widget, allocation):
    self.__sourceview.scroll_to_mark(self.__sourceview.get_buffer().get_insert(), 0.25, False, 0, 0)

使用这种方法会出现明显的闪烁。在上面的 __source_resize 中放置 1s sleep 表明 GtkSourceView 在几遍中得到重新调整(在源突出显示之前和之后可见地绘制,以及一些额外的验证。)

是否有另一种方法可以强制 GtkSource.View 计算行高并执行验证而不在屏幕上绘图,或者在我设置缓冲区内容时强制它立即计算行高而不稍后将其推迟到空闲作业?如果不是,大约需要覆盖多少 GtkSource.View 控件才能获得所需的行为?

注意:我尝试使用 Gtk.Stack 在不可见的“后”视图中完成工作,并在稍后使用 Gtk.idle_add 使其可见,但我的印象是视图的可见性是行验证的关键。至少到目前为止,它没有提供预期的结果。

4

1 回答 1

1

Gtk.Stack 方法有效。它需要特定的操作顺序。这是我现在拥有的解决方案的摘录(为清楚起见而修改):

class MyClientWindow:
  def __init__(self):
    self.__stack = Gtk.Stack()
    ...
  def __switch_doc(content, line):
    buffer = GtkSource.Buffer()
    buffer.set_text(content)
    # buffer style settings are applied here
    ...
    iter = buffer.get_iter_at_line(line)
    buffer.place_cursor(iter)
    source_view = GtkSource.View.new_with_buffer(buffer)
    prev_sw = self.__stack.get_visible_child()
    next_sw = Gtk.ScrolledWindow()
    next_sw.add(source_view)
    next_sw.show_all()
    self.__stack.add(next_sw)
    GObject.idle_add(lambda: self.__switch_view(prev_sw, next_sw))
  def __switch_view(self, prev_sw, next_sw):
    source_view = next_sw.get_child()
    buffer = source_view.get_buffer()
    source_view.scroll_to_iter(buffer.get_iter_at_mark(buffer.get_insert()), 0, True, 0, 0.5)
    if prev_sw:
      self.__stack.remove(prev_sw)

我每次都重新创建 GtkSourceView 和父 GtkScrollWindow。这可能会有所优化(通过保留堆栈中的旧视图而不是删除它们。)

在将 GtkScrollWindow 添加到堆栈容器之前显示它是很重要的。否则,如果使用 scroll_to_iter 移动到文本中的新位置,稍后显示时将缺少着色。(我不知道这是否是一个错误。)

在添加之前显示小部件使其成为堆栈的“可见子”,但仅在某种意义上它由 get_visible_child 方法返回。但是,它不会将其呈现到屏幕上。

当旧的孩子被移除(或新的孩子被 set_visible_child 方法激活)时,绘图开始,由于上面使用了 idle_add,发生在 GtkSourceView 的行验证之后。因此,可以使用 scroll_to_iter 来执行滚动,而不是使用 scroll_to_mark,这将进一步推迟操作。

于 2015-11-18T12:28:13.110 回答