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.
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