3

GTKscrolledWindow 内にある多数の水平ドロップダウンとテキスト ボックスを備えたフォーム インターフェイスがあります。ウィンドウには無制限の数のフォームがあるため、フォームを水平方向に配置する必要があります (フォームの表を考えてください)。

オペレーターが画面の右側にある次のフォームコントロールにタブ移動すると、GTKScrolledWindow が右に自動スクロールされますか?

関連する質問は、フォーカスされた要素 (ボタンなど) が親のスクロール ウィンドウに表示されているかどうかを検出する方法です。

ありがとう。

4

3 に答える 3

4

説明で GTK+ C API を使用していることを気にしないでください。ソリューションは PyGTK に簡単に変換でき、原則は同じままです。

2 番目の質問から始めます。テストするウィジェットがわかっている場合は、呼び出し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"ウィジェットを含むコンテナに接続されたイベントを処理できます。シグナル ハンドラーで、フォーカスされたウィジェットが表示されているかどうかを確認する必要があります。そうでない場合は、その位置を決定し、適切にスクロールします。

そのためには、スクロールされた領域全体でウィジェットの位置を検出する必要があります。スクロールをサポートしていないコンテナを使用している場合(ビューポートによって調整されるなどGtkHBoxGtkScrolledWindow、コンテナを基準にしてフォーカスされたウィジェットの座標を取得できます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"ます。シグナルの場合は、コンテナも引数として取得します。

于 2011-08-02T12:37:08.187 に答える
2

まず、最初。焦点をどのように検出しますか?GtkWidget::focusシグナルに接続します。そのコールバックでは、ウィンドウを好きな場所にスクロールできます。その方法は、GtkScrolledWindowのGtkAdjustmentを取得し、それを適切に移動して必要なものを表示する必要があります。

于 2011-08-02T12:17:39.000 に答える
2

Michyの答えに基づいて、私がしたことは次のとおりです。

スクロールされたウィンドウを自動スクロールするには、コンストラクターで実行します。

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
于 2012-01-18T15:03:47.277 に答える