Mittwoch, 4. Mai 2016

Eclipse lambda driven UI creation

About

With the addition of lambda expressions to the Java 8 language, you can now create nice APIs for reducing boilerplate code. One of tedious tasks has always been the creation of UI code as it involves lots of boilerplate code and keeping track of what control/widget is a child of another. This article introduces a small helper library I use in my projects. It is about a thin lambda driven API for creating structured UI code.

Conventional UI code

The following code will create a simple UI form:
private Text text;

public void createUIConventional(Composite parent) {
    parent.setLayout(GridLayoutFactory.swtDefaults().numColumns(3).create());

    Label label = new Label(parent, SWT.NONE);
    label.setText("Selection");

    ComboViewer viewer = new ComboViewer(parent, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY);
    customizeComboViewer(viewer);
    viewer.getCombo().setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    Button button = new Button(parent, SWT.NONE);
    button.setText("Apply");
    button.addSelectionListener(new SelectionAdapter() {
        @Override
        public void widgetSelected(SelectionEvent e) {
            text.setText("Selection:  " + viewer.getCombo().getText());
        }
    });

    text = new Text(parent, SWT.READ_ONLY | SWT.BORDER);
    text.setLayoutData(
            GridDataFactory.swtDefaults().span(3, 1).grab(true, true).align(SWT.FILL, SWT.FILL).create());
}


As you can see, SWT requires that you always create a new Control/Widget as a child to an existing one, i.e. you have to provide the parent as the first constructor parameter.
Furthermore, if you have lots of UI elements to create, the readability of the code quickly decreases and you can hardly see the hierarchy of the UI widgets WITHIN the code.

In the past, I often used local code blocks to denote the hierarchy of UI controls within the code to achieve better readability.

Lambda driven UI code

The above example can now be rewritten as follows:

 private SwtUI root;

 public void createUI(Composite parent) {
  root = SwtUI.wrap(parent);
  root.layout(GridLayoutFactory.swtDefaults().numColumns(3).create())//
    .child(() -> SwtUI.create(Label::new)//
      .text("Selection"))//
    .child(() -> ViewerUI.createViewer(ComboViewer::new, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY)//
      .id("selectionCombo")//
      .customizeViewer(this::customizeComboViewer)//
      .layoutData(new GridData(GridData.FILL_HORIZONTAL)))//
    .child(() -> SwtUI.create(Button::new)//
      .text("Apply")//
      .on(SWT.Selection, this::onButtonClick))//
    .child(() -> SwtUI.create(Text::new, SWT.READ_ONLY | SWT.BORDER)//
      .id("textField")//
      .layoutData(GridDataFactory.swtDefaults().span(3, 1).grab(true, true).align(SWT.FILL, SWT.FILL)
        .create()));
 }

Now, by using method pointers internally, instantiating a control/widget does not need its parent any more as it will always be parented within the current context.

You can find the code at:

https://github.com/erdalkaraca/lambda-ui

Check it out into your workspace and experiment with it. Do not hesitate to give feedback.

Keine Kommentare:

Kommentar veröffentlichen