滚动到 GtkListBox 中的选定行

Scroll to selected row in GtkListBox

我有点没脑子了。我想要一个非常简单的事情:能够以编程方式 select 给定的 GtkListBox 行,然后滚动列表框(包含在 ScrolledWindowViewport 中) .

选择一行很简单(我的代码是 Go & gotk3,但这并不重要):

listBox.SelectRow(row)

但事实证明,滚动到该行是一项真正的挑战。无论我尝试过什么,我都失败了:

更新: 我已经尝试了这里提出的建议:,但没有成功,因为仍然没有滚动发生:

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

我也使用下面的代码对 rowToSelect 的 child 进行了同样的尝试,但无济于事:

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

所以,我遇到了同样的问题,但设法让它在我的案例中起作用。我认为我的解决方案很有可能也适用于您。

由于 grab_focus 方法不起作用,我开始使用 listbox_get_row_at_y 实施解决方案。非常不满意,但希望它会起作用。而且.. 它没有用,因为 get_row_at_y 总是 return null,对于我提供的所有 y 值。而且我知道列表框不是空的。所以这让我意识到我正在尝试聚焦我刚刚添加到列表框中的行。该行尚未实现,它无法聚焦,因为它还没有准备好。

所以我更改了代码以填充列表框,等待 100 毫秒超时,然后才调用 grab_focus。这奏效了!

我实际上正在使用一个为我包装超时调用的库,但我认为您可以为此目的在 'raw' gtk 中使用 g_timeout_add

请注意,这意味着在预先已填充的列表框中调用 grab_focus 并且在屏幕上实现的项目应该可以直接工作。如果这是你的情况,那么这对你没有帮助。

感谢 Emmanuel Touzery 的提示,我终于成功了。我不必使用计时器,但问题确实是在填充列表框时该行尚未实现,因此不可能发生坐标转换。

我所做的是使用 GLib 的 idle_add() 安排滚动,这使得它稍后在下游发生,并且似乎效果很好:请参阅 this commit 了解详细信息。

简而言之,这一切都归结为以下代码:

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() 而非在填充列表框的代码中调用 上述函数