自动滚动 gtkscrolledwindow

发布于 2024-11-27 15:03:33 字数 206 浏览 3 评论 0原文

我有一个表单界面,其中有大量水平下拉列表和文本框,位于 GTKscrolledWindow 内。表单必须水平对齐,因为窗口中有无限数量的表单(想想表单的表格)。

当操作员切换到屏幕右侧的下一个表单控件时,是否(可能/如何)自动将 GTKScrolledWindow 滚动到右侧?

相关问题是如何检测焦点元素(按钮等)在其父滚动窗口中是否可见。

谢谢。

I have a form interface with a large number of horizontal drop down and text boxes that are inside a GTKscrolledWindow. The form has to be aligned horizontally because there are an unlimited number of forms in the window (think tabel of forms).

Is it (possible/how do I) auto-scroll the GTKScrolledWindow to the right when the operator tabs to the next form control which is off to the right of the screen.?

Related question would be how do I detect if the focused element (button etc) is visible in it's parent scrolledwindow.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月亮坠入山谷 2024-12-04 15:03:33

我希望您不介意我在描述中使用 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 - adjustment.page_size。聚焦的小部件作为两个信号的信号处理程序参数传递,在“set-focus-child”信号的情况下,您还可以将容器作为参数传递。

I hope you don't mind I am using GTK+ C API in the description, the sollution could be converted to the PyGTK easily and the principles remains the same.

Starting with the second question - if you know which widget to test, you can detect its visibility by calling gtk_widget_translate_coordinates(child, parent, 0, 0, &x, &y) to get the position of the child relative to the parent. By gtk_widget_get_allocation() you get the size of parent and child and you simply test if whole child rectangle is in the scrolled window.

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;
}

You can obtain the curently focused widget in window by gtk_window_get_focus () or you can detect it when focus is changed.

In the autoscroll problem you can handle "focus" signal connected to the widget which can be focussed or the "set-focus-child" event connected to the container containing the widgets. In the signal handler you should check, if the focused widget is visible. If not, determinate its position and scroll properly.

To do so you have to detect the position of the widget inside the whole scrolled area. If you are using some container which does not support scrolling (such GtkHBox) iside GtkScrolledWindow (adapted by viewport), you can get the coordinates of the focused widget relative to the container by gtk_widget_translate_coordinates() again - now using the container instead of scrolled window. The value of the adjustment, if using GtkViewport, the adjustment value correspond to the position in pixels in the scrolled area, so setting adjustment value to x relative coordinate will do scrolling. So the important part of the handler could be

    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);

The maximal adjustment value allowed is adjustment.upper - adjustment.page_size. The focused widget is passed as signal handler argument for both signals, in the case of "set-focus-child" signal you get also the container as argument.

疯狂的代价 2024-12-04 15:03:33

这就是我根据米奇的回答所做的。

要使滚动窗口自动滚动,请在构造函数中运行:

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

Here's what I did, based on Michy's answer.

To make a scrolled window auto-scroll, run in the constructor:

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
信仰 2024-12-04 15:03:33

第一,第一。
如何检测焦点?您连接到 GtkWidget::focus 信号。
在该回调中,您可以将窗口滚动到您喜欢的任何位置,如何做到这一点,您需要获取 GtkScrolledWindowGtkAdjustment 并相应地移动它以显示您想要的内容。

First, the first.
How do you detect the focus ? You connect to GtkWidget::focus signal.
And in that callback you can scroll the window to whereever you like, how to do that, you need to get the GtkAdjustment of GtkScrolledWindow and move it accordinly to show what you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文