Прокрутите до выбранной строки в GtkListBox - PullRequest
1 голос
/ 18 июня 2020

У меня здесь немного идей. Мне нужна очень простая вещь: иметь возможность программно выбрать заданную строку GtkListBox, а затем прокрутить список (который заключен в ScrolledWindow и Viewport).

Выбор строки тривиально (мой код - Go & gotk3 , но это не так важно):

listBox.SelectRow(row)

Но прокрутка к строке оказалась реальной проблемой. Что бы я ни пробовал, мне это не удалось:

  • Я попытался сфокусировать строку, но это ничего не помогло
  • Я попытался определить координату Y строки, используя gtk_widget_translate_coordinates(), но это возвращает -1 для любой строки
  • Возможно, я смогу узнать, какая строка находится вверху и внизу списка, и использовать это для прокрутки ScrolledWindow, но я не могу понять, как это сделать .

Обновление: Я пробовал то, что предлагается здесь: Вручную прокрутите до дочернего элемента в Gtk.ScrolledWindow , но это не сработало как по-прежнему не происходит прокрутки:

listbox.SelectRow(rowToSelect)
listbox.SetFocusVAdjustment(listbox.GetAdjustment())
if rowToSelect != nil {
    rowToSelect.GrabFocus()
}

Я также пробовал то же самое с дочерним элементом rowToSelect, используя приведенный ниже код, но безрезультатно:

if c, err := rowToSelect.GetChild(); err == nil {
    c.GrabFocus()
}

Ответы [ 2 ]

1 голос
/ 23 июля 2020

Я наконец-то понял это благодаря подсказке Эммануэля Тузери. Мне не пришлось go использовать таймеры, но проблема действительно заключалась в том, что на момент заполнения поля списка строка еще не была реализована, поэтому перевод координат не мог произойти.

Я спланировал прокрутку с помощью idle_add() GLib, что позволяет сделать это позже, и это, похоже, сработало отлично: см. этот коммит для подробностей.

In Короче говоря, все сводится к следующему коду:

func ListBoxScrollToSelected(listBox *gtk.ListBox) {
    // If there's selection
    if row := listBox.GetSelectedRow(); row != nil {
        // Convert the row's Y coordinate into the list box's coordinate
        if _, y, _ := row.TranslateCoordinates(listBox, 0, 0); y >= 0 {
            // Scroll the vertical adjustment to center the row in the viewport
            if adj := listBox.GetAdjustment(); adj != nil {
                _, rowHeight := row.GetPreferredHeight()
                adj.SetValue(float64(y) - (adj.GetPageSize()-float64(rowHeight))/2)
            }
        }
    }
}

Вышеупомянутая функция должна вызываться с использованием glib.IdleAdd(), а не в коде, заполняющем поле списка.

1 голос
/ 22 июля 2020

Итак, у меня была та же проблема, но мне удалось заставить ее работать в моем случае. Я думаю, есть хорошие шансы, что мое решение сработает и для вас.

Поскольку метод grab_focus не работал, я начал реализовывать обходное решение, используя listbox_get_row_at_y. В высшей степени неудовлетворительно, но, надеюсь, это сработает. И .. это не сработало, потому что get_row_at_y всегда возвращал null для всех значений y, которые я ему скармливал. И я знал, что список не пуст. Это заставило меня понять, что я пытался сфокусировать строку, которую только что добавлял в список ... Строка еще не была реализована, ее нельзя было сфокусировать, потому что она еще не была готова для этого.

Итак, я изменил свой код, чтобы заполнить список, подождать тайм-аут 100 мс и только затем позвонить grab_focus. И это сработало!

На самом деле я использую библиотеку, которая обертывает для меня вызов тайм-аута, но я думаю, вы могли бы использовать g_timeout_add в 'raw' gtk для этой цели.

Обратите внимание, что это означает, что вызов grab_focus в списке, который уже был заполнен заранее, и элементы, реализованные на экране, должны работать напрямую. Если это ваша ситуация, то это вам не поможет.

...