mercoledì 9 febbraio 2011

ScrollableComposite: quello che la documentazione non dice

Come dice la documentazione, lo ScrolledComposite consente di visualizzare il suo contenuto con lo scorrimento delle barre verticali e orizzontali.

La documentazione è abbastanza dettagliata, fornisce anche un esempio.


public static void main(String[] args)
{
Display display = new Display();
Color red = display.getSystemColor(SWT.COLOR_RED);
Color blue = display.getSystemColor(SWT.COLOR_BLUE);
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());

// set the size of the scrolled content - method 1
final ScrolledComposite sc1 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
final Composite c1 = new Composite(sc1, SWT.NONE);
sc1.setContent(c1);
c1.setBackground(red);
GridLayout layout = new GridLayout();
layout.numColumns = 4;
c1.setLayout(layout);
Button b1 = new Button(c1, SWT.PUSH);
b1.setText("first button");
c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));

// set the minimum width and height of the scrolled content - method 2
final ScrolledComposite sc2 = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
sc2.setExpandHorizontal(true);
sc2.setExpandVertical(true);
final Composite c2 = new Composite(sc2, SWT.NONE);
sc2.setContent(c2);
c2.setBackground(blue);
layout = new GridLayout();
layout.numColumns = 4;
c2.setLayout(layout);
Button b2 = new Button(c2, SWT.PUSH);
b2.setText("first button");
sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));

Button add = new Button(shell, SWT.PUSH);
add.setText("add children");
final int[] index = new int[]{0 };
add.addListener(SWT.Selection, new Listener()
{

public void handleEvent(Event e)
{
index[0]++;
Button button = new Button(c1, SWT.PUSH);
button.setText("button " + index[0]);
// reset size of content so children can be seen - method 1
c1.setSize(c1.computeSize(SWT.DEFAULT, SWT.DEFAULT));
c1.layout();

button = new Button(c2, SWT.PUSH);
button.setText("button " + index[0]);
// reset the minimum width and height so children can be seen - method 2
sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
c2.layout();
}
});

shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}


L'esempio funziona, aggiungendo del contenuto (in questo caso dei bottoni) le scrollbar appaiono non appena il contenuto diventa più grande dell'area visibile.
Nella pratica però, una situazione così semplice (composite direttamente nella shell) non avviene praticamente mai, è molto più probabile che ci sia un meccanismo di scatole cinesi.. composite dentro composite dentro composite.
Se proviamo a mettere un Composite parent che contiene il nostro ScrollableComposite, già rischiamo che il meccanismo non funzioni più. Perchè?

La documentazione non dice che il parent di uno ScrollableComposite deve sempre avere un layout di tipo FillLayout. Questo è fondamentale per farlo funzionare.

Sotto un esempio più complesso del precedente:


public static void main(String[] args)
{
Display display = new Display();
Color blue = display.getSystemColor(SWT.COLOR_BLUE);
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());

FormToolkit toolkit = new FormToolkit(Display.getCurrent());

Composite container = toolkit.createComposite(shell, SWT.NONE);

// container.setLayout(new GridLayout()); NON FUNZIONA!!!!
container.setLayout(new FillLayout());

container.setLayoutData(new GridData(GridData.FILL_BOTH));

Section section = toolkit.createSection(container, ExpandableComposite.TWISTIE
| ExpandableComposite.COMPACT
| ExpandableComposite.TITLE_BAR);

section.setText("Section");
section.setLayout(new GridLayout());
section.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
section.setVisible(false);

// set the minimum width and height of the scrolled content - method 2
final ScrolledComposite sc2 = new ScrolledComposite(section, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
sc2.setExpandHorizontal(true);
sc2.setExpandVertical(true);
final Composite c2 = new Composite(sc2, SWT.NONE);
sc2.setContent(c2);
c2.setBackground(blue);
GridLayout layout2 = new GridLayout();
layout2.numColumns = 4;
c2.setLayout(layout2);

for (int i = 0; i < 100; i++)
{
toolkit.createButton(c2, "button" + i, SWT.PUSH);
}

sc2.setMinSize(c2.computeSize(SWT.DEFAULT, SWT.DEFAULT));
section.setClient(sc2);
section.setVisible(true);
section.setExpanded(false);

shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}


Il layout di tipo Fill non consente di dimensionare a proprio piacimento lo spazio per posizionare per esempio due composite affiancati o uno sopra l'altro con altezze differenti (come invece consente il GridLayout). Ma ci sono altri meccanismi utili per fare questo come per esempio il SashForm.

Nessun commento:

Posta un commento