Прокрутите до нижней части Scrollable, если содержимое изменяется в Python GTK - PullRequest
1 голос
/ 30 сентября 2019

Я создаю графический интерфейс с прокручиваемым элементом, который содержит Textview. Я использую Textbuffer для добавления текста в текстовое представление;это работает хорошо, но когда содержимое становится большим, полоса прокрутки остается на своем месте. Я создал свой графический интерфейс с Glade.

Я прочитал документы, но я не смог найти такой метод, как scrollToBottom() или что-нибудь еще.

Так как я могу убедиться, что прокрутка всегдавнизу, когда выводится новый текст?

1 Ответ

2 голосов
/ 30 сентября 2019

Для прокрутки в GtkTextView вы должны использовать маркеры в GtkTextBuffer. Объекты GtkTextMark автоматически обновляются, поэтому просто создайте маркер один раз при создании TextBuffer.

  1. Создайте объект GtkTextBuffer и GtkTextMark
  2. Создайте GtkTextView
  3. Каждый раз, когда вы добавляете текст, вы можете вызвать gtk_text_view_scroll_to_mark , чтобы прокрутить в конце

Вот как это сделать:

C

GtkTextView *text_view;
GtkTextMark *text_mark_end;

void create_text_view () {
  text_view = gtk_text_view_new ();

  /* get the text buffer */
  GtkTextBuffer *text_buffer;
  text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));

  /* create an auto-updating 'always at end' marker to scroll */
  GtkTextIter text_iter_end;
  gtk_text_buffer_get_end_iter (text_buffer, &text_iter_end);
  text_mark_end = gtk_text_buffer_create_mark (text_buffer,
                                               NULL,
                                               &text_iter_end,
                                               FALSE);
}

void append_text(const gchar *text) {
  if (text) {
    /* get the text buffer */
    GtkTextBuffer *text_buffer;
    text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));

    /* get an end iter */
    GtkTextIter text_iter_end;
    gtk_text_buffer_get_end_iter (text_buffer, &text_iter_end);

    /* append text */
    gtk_text_buffer_insert (text_buffer, &text_iter_end);

    /* now scroll to the end using marker */
    gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (text_view),
                                  text_mark_end,
                                  0., FALSE, 0., 0.);
  }
}

void destroy_text_view () {
  g_object_unref (text_mark_end);
  gtk_widget_destroy (text_view);
}

Python

#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class TextView(Gtk.TextView):
  def __init__(self):
    Gtk.TextView.__init__(self)
    # create mark for scrolling
    text_buffer = self.get_buffer()
    text_iter_end = text_buffer.get_end_iter()
    self.text_mark_end = text_buffer.create_mark("", text_iter_end, False)

  def append_text(self, text):
    # append text
    text_buffer = self.get_buffer()
    text_iter_end = text_buffer.get_end_iter()
    text_buffer.insert(text_iter_end, text)
    # now scroll using mark
    self.scroll_to_mark(self.text_mark_end, 0, False, 0, 0)

class Window(Gtk.Window):
  def __init__(self):
    Gtk.Window.__init__(self)
    self.set_title('Test GtkTextView scrolling')
    self.set_default_size(400, 300)

    self.grid = Gtk.Grid()
    self.scrolled_win = Gtk.ScrolledWindow()
    self.text_view = TextView()
    self.button = Gtk.Button(label='Append text')
    self.scrolled_win.set_hexpand(True)
    self.scrolled_win.set_vexpand(True)

    self.scrolled_win.add(self.text_view)
    self.grid.add(self.scrolled_win)
    self.grid.add(self.button)
    self.add(self.grid)

    self.connect('destroy', Gtk.main_quit)
    self.button.connect('clicked', self.on_button_clicked)
    self.show_all()

  def on_button_clicked(self, widget):
    self.text_view.append_text('Hello\n' * 5);

if __name__ == '__main__':
  win = Window()
  Gtk.main()

Примечание:

Также имеется функция gtk_text_view_scroll_to_iter . Это не очень полезно, потому что GtkTextView использует анимированную прокрутку (анимированную прокрутку можно увидеть, например, с помощью gedit с PAGE вверх / вниз). В отличие от прокрутки на основе маркера, прокрутка на основе iter не очень хорошо работает с возможностью анимированной прокрутки GtkTextView:

https://developer.gnome.org/gtk3/stable/GtkTextView.html#gtk-text-view-scroll-to-iter

Обратите внимание, что эта функция использует вычисленные в настоящее времявысота строк в текстовом буфере. Высота строк вычисляется в обработчике бездействия;поэтому эта функция может не дать желаемого эффекта, если она вызывается до вычисления высоты. Чтобы избежать странностей, рассмотрите возможность использования gtk_text_view_scroll_to_mark (), которая сохраняет точку для прокрутки после проверки строки.

...