我有一个表单界面,其中包含大量水平下拉菜单和 GTKscrolledWindow 内的文本框。表格必须水平对齐,因为窗口中有无限数量的表格(想想表格表格)。
当操作员选项卡到屏幕右侧关闭的下一个表单控件时,它(可能/我如何)自动向右滚动 GTKScrolledWindow。?
相关问题是如何检测焦点元素(按钮等)是否在其父滚动窗口中可见。
谢谢。
我有一个表单界面,其中包含大量水平下拉菜单和 GTKscrolledWindow 内的文本框。表格必须水平对齐,因为窗口中有无限数量的表格(想想表格表格)。
当操作员选项卡到屏幕右侧关闭的下一个表单控件时,它(可能/我如何)自动向右滚动 GTKScrolledWindow。?
相关问题是如何检测焦点元素(按钮等)是否在其父滚动窗口中可见。
谢谢。
我希望你不介意我在描述中使用 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
)iside 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"
您还将容器作为参数。
首先,第一个。你如何检测焦点?你连接到GtkWidget::focus信号。在该回调中,您可以将窗口滚动到您喜欢的任何位置,如何做到这一点,您需要获取GtkScrolledWindow的GtkAdjustment并相应地移动它以显示您想要的内容。
根据 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