The description of Gtk::Layout says
Infinite scrollable area containing child widgets and/or custom drawing
I put a Gtk::Layout inside a Gtk::ScrolledWindow, gave the Gtk::Layout a size of 400x400 and then placed a Gtk::Button at (450, 450), but the scrollbars only appeared until the scrolled window was resized to 400x400, not (450+button-width x 450+button-height). So I had to move the bottom-right corner of the layout by connecting a handler to button's signal_size_allocate() signal and manually call Gtk::Layout::set_size() function to resize it up to button's boundary. Now the scrolled window shows scrollbars to reach the button. Up to this everything was OK.
class LayoutWindowTest : public ApplicationWindow {
ScrolledWindow sw;
Layout l;
Button b;
public:
LayoutWindowTest()
: l(), b("test") {
set_title("layout test");
set_size_request(400, 400);
sw.set_hadjustment(l.get_hadjustment());
sw.set_vadjustment(l.get_vadjustment());
l.set_size(400, 400);
sw.add(l);
add(sw);
// b.get_allocation() won't work because button has not been allocated a
// size yet
b.signal_size_allocate().connect(
[this](Allocation& btn_sz) {
l.set_size(btn_sz.get_x() + btn_sz.get_width(),
btn_sz.get_y() + btn_sz.get_height());
});
l.put(b, 450, 450);
show_all_children();
}
virtual ~LayoutWindowTest() {}
};
Initial window showing scrollbars and then scrolled to bottom-right corner to show button
Now I need to do the same thing for the top-left corner, i.e. put the button out of visible boundary of scrolled window and then use the scrollbars to reach the button. I tried putting the button at (-10, -10), but unlike the previous case I can't set layout's top-left corner with code by resizing it, so can't move the layout's scrollbars. When I resize the scrolled window manually by its top-left corner the button moves towards top-left with it instead of staying there. How to remedy this situation?
Initial window with button at (-10, -10) and no scrollbars, tried resizing the window by top-left handle but button moves with it
In short, how can I scroll in both top-left and bottom-right directions infinitely?
My Goal is to have a Button with a background image and ontop of these a Label.
I want to position the label in the centre of the button and vertically allign it's text. I want the button to expand in propotion to the number of characters in the label. What is the best type of panel to use to build this type of composite widget as I am running into problems with using an AbsolutePanel as it doesn't dynamically grow with it's child elements.
private PushButton button;
private Label label = new Label();
private AbsolutePanel panel = new AbsolutePanel();
private Image image = new Image("images/rectangle_blue.png");
public ExpandingRectangularButton(String text)
{
label.setText(text);
String width = "120px";
String height = "160px";
image.setWidth(width);
image.setHeight(height);
button = new PushButton(image);
panel.add(button, 0, 0);
panel.setWidth(width);
panel.setHeight(height);
initWidget( panel );
}
What is the best type of panel to use in this case? I have tried flow, horizontal and flextables but I can't get these to stack widgets on top of each other correctly
FlowPanel??.
A FlowPanel arranges components in a directional flow, much like lines of text in a paragraph.
My purpose is to draw in the CENTER of the composite. Actually, I have an rcp view and I'm drawing some shapes inside it. this is the code that I use :
display = parent.getDisplay();
white= display.getSystemColor(SWT.COLOR_WHITE);
parent.setLayout(new FillLayout(SWT.VERTICAL));
// Create the ScrolledComposite to scroll horizontally and vertically
final ScrolledComposite sc =new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
sc.setMinHeight(100);
sc.setMinWidth(100);
sc.setSize(100,100);
Composite child = new Composite(sc,SWT.NONE);
child.setLayout(new FillLayout());
child.layout(true);
parent.addListener (SWT.Resize, new Listener () {
public void handleEvent (Event e) {
x = child.getBounds().width/2;
y = child.getBounds().height/2;
child.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
dessin(gc); // to raw the circle
}
});
sc.getDisplay().update();
}
});
I defined the view with a ratio (so when the view is empty I get the wanted size)...I don't know the exact size of the view since it can be resized by the user at anymoment, or when an editor is opened... So, my problem is how to draw just in the center of the view and keep the drawings in the center even if the view is resized...
PS: Using (Point.x and point.y), I get (0,0) when the view appears first, then I get other values...
Pleaaaaaaaaaaaaaase help
You can use getOrigin() method on ScrolledComposite, which will return Point instance with the point in the content that currently appears in the top left corner of the scrolled composite. See docs getOrigin method on ScrolledComposite.
With that information and size of the component which you'll get from getBounds() method you can easily calculate the 'real' center.
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.
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.
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
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.
I've got a SplitLayoutPanel. In the North cell, I've got a ScrollPanel
with a tree on it.
I want this ScrollPanel height to be the same of the north cell, so
when the tree expand, a scroll appears. The size of this ScrollPanel
must changed when the north cell is resized.
I've tried with RequireResizes but parent does not send size
information... An ideal approach should be that ProvidesSize widgets call onResize method with available size for the RequiresSize widget children
I'm very confused. How to configure SplitLayoutPanel to have cell
children resized ?
Thanks
Create a class that extends Composite and implement RequiresResize; like so:
public class MyScrollPanel extends Composite implements RequiresResize {
private ScrollPanel scrollPanel;
public MyScrollPanel() {
scrollPanel = new ScrollPanel();
initWidget(scrollPanel);
}
public void onResize() {
// do something to your scrollpanel
}
}
Then add MyScrollPanel to the north cell in your SplitLayoutPanel.
EDIT
However. It turns out ScrollPanel already has the desired behavior by default. A ScrollPanel added to a SplitLayoutPanel cell will automatically fill the size of the cell, even on resize. And any ScrollPanel child widget larger than available space will cause a scrollbar to appear.
But make sure you're adding the SplitLayoutPanel to the RootLayoutPanel by doing
RootLayoutPanel.get().add(splitLayoutPanel);