Автоматическая прокрутка окна gtkscrolled - PullRequest
3 голосов
/ 01 августа 2011

У меня есть интерфейс формы с большим количеством горизонтальных выпадающих и текстовых полей, которые находятся внутри GTKscrolledWindow.Форма должна быть выровнена по горизонтали, потому что в окне неограниченное количество форм (подумайте о форме форм).

Возможно (как / возможно) автоматически прокрутить окно GTKScrolledWindow вправо, когда оператор перейдет к следующему элементу управления формы, который находится справа от экрана?

Смежный вопрос: как определить, виден ли сфокусированный элемент (кнопка и т. Д.) В родительском окне прокрутки?

Спасибо.

Ответы [ 3 ]

3 голосов
/ 02 августа 2011

Надеюсь, вы не возражаете, я использую GTK + C API в описании, решение может быть легко преобразовано в PyGTK, и принципы остаются прежними.

Начиная со второго вопроса - если вы знаете, какой виджет тестировать, вы можете определить его видимость, вызвав gtk_widget_translate_coordinates(child, parent, 0, 0, &x, &y), чтобы узнать положение дочернего элемента относительно родительского.По gtk_widget_get_allocation() вы получаете размер родительского и дочернего элементов и просто проверяете, находится ли весь дочерний прямоугольник в прокручиваемом окне.

gboolean is_visible_in (GtkWidget *child, GtkWidget *scrolled)
{
    gint x, y;
    GtkAllocation child_alloc, scroll_alloc;
    gtk_widget_translate_coordinates (child, scrolled, 0, 0, &x, &y);
    gtk_widget_get_allocation(child, &child_alloc);
    gtk_widget_get_allocation(scrolled, &scroll_alloc);

    return (x >= 0 && y >= 0) 
        && x + child_alloc.width <= scroll_alloc.width
        && y + child_alloc.height <= scroll_alloc.height;
}

Вы можете получить виджет, сфокусированный в окне, с помощью gtk_window_get_focus () или выможет обнаружить его при изменении фокуса.

В задаче автоматической прокрутки вы можете обрабатывать сигнал "focus", подключенный к виджету, который может быть сфокусирован, или событие "set-focus-child", подключенное к контейнеру, содержащему виджеты.В обработчике сигналов вы должны проверить, виден ли сфокусированный виджет.Если нет, определите его положение и правильно прокрутите.

Для этого вы должны определить положение виджета внутри всей области прокрутки.Если вы используете какой-то контейнер, который не поддерживает прокрутку (например, GtkHBox), то есть GtkScrolledWindow (адаптировано для области просмотра), вы можете получить координаты сфокусированного виджета относительно контейнера снова gtk_widget_translate_coordinates() - теперь используя контейнервместо прокручиваемого окна.Значение регулировки, если используется GtkViewport, значение регулировки соответствует позиции в пикселях в прокручиваемой области, поэтому при установке значения регулировки на относительную координату x будет выполняться прокрутка.Таким образом, важной частью обработчика может быть

    GtkWidget *scrolled = /* The scrolled window */
    GtkWidget *container = /* The container in the scrolled window */
    GtkWidget *focused = /* The focused widget */

    GtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( 
        GTK_SCROLLED_WINDOW(scrolled));
    gint x, y;
    gtk_widget_translate_coordinates (focused, container, 0, 0, &x, &y);
    gtk_adjustment_set_value(hadj, min(x, maximal adjustment value allowed);

Максимально допустимое значение корректировки - Adjustment.upper - Adjust.page_size.Сфокусированный виджет передается в качестве аргумента обработчика сигнала для обоих сигналов, в случае сигнала "set-focus-child" вы также получаете контейнер в качестве аргумента.

1 голос
/ 18 января 2012

Вот что я сделал, основываясь на ответе Мичи.

Для автоматической прокрутки окна прокрутки запустите в конструкторе: FocusScroll (scrolledwindow).

class FocusScroll(object):
"""
Get a gtk.ScrolledWindow which contains a gtk.Viewport.
Attach event handlers which will scroll it to show the focused widget.
"""
def __init__(self, scrolledwindow):
    self.scrolledwindow = scrolledwindow
    self.viewport = scrolledwindow.get_child()
    assert isinstance(self.viewport, gtk.Viewport)
    self.main_widget = self.viewport.get_child()
    self.vadj = scrolledwindow.get_vadjustment()
    self.window = self.get_window(scrolledwindow)

    self.viewport.connect('set-focus-child', self.on_viewport_set_focus_child)

def get_window(self, widget):
    if isinstance(widget, gtk.Window):
        return widget
    else:
        return self.get_window(widget.get_parent())

def is_child(self, widget, container):
    """
    Go recursively over all children of container, to check if widget is
    a child of it.
    """
    for child in container.get_children():
        if child is widget:
            return True
        elif isinstance(child, gtk.Container):
            if self.is_child(widget, child):
                return True
    else:
        return False

def on_viewport_set_focus_child(self, _viewport, _child):
    idle_add(self.scroll_slide_viewport)

def scroll_slide_viewport(self):
    """Scroll the viewport if needed to see the current focused widget"""
    widget = self.window.get_focus()
    if not self.is_child(widget, self.main_widget):
        return

    _wleft, wtop = widget.translate_coordinates(self.main_widget, 0, 0)
    wbottom = wtop + widget.get_allocation().height

    top = self.vadj.value
    bottom = top + self.vadj.page_size

    if wtop < top:
        self.vadj.value = wtop
    elif wbottom > bottom:
        self.vadj.value = wbottom - self.vadj.page_size
1 голос
/ 02 августа 2011

Сначала первый. Как вы определяете фокус? Вы подключаетесь к GtkWidget :: focus сигналу. И в этом обратном вызове вы можете прокрутить окно в любое удобное для вас время. Как это сделать, вам нужно получить GtkAdjustment из GtkScrolledWindow и перемещать его, чтобы показать, что вы хотите. 1007 *

...