How to Create a Widget

A widget is the main way to render information on the display. A set of pre-defined widgets is described in the Widgets and Examples section.

If the needed widget does not already exist, it is possible to create it from scratch (or by derivating another one).

To create a custom widget, a new class should be created, extending the Widget class. Widget subclasses have to implement two methods and may override optional methods, as explained in the following sections.

Implementing the mandatory methods

Computing the optimal size of the widget

The computeContentOptimalSize() method is called by the MWT framework in order to know the optimal size of the widget. The optimal size of the widget should be big enough to contain all the drawings of the widget.

The Size parameter of the computeContentOptimalSize() method initially contains the size available for the widget. An available width or height equal to Widget.NO_CONSTRAINT means that the optimal size should be computed without considering any restriction on the respective axis. Before the method returns, the size object should be set to the optimal size of the widget.

When implementing this method, the getStyle() method may be called in order to retrieve the style of the widget.

For example, the following snippet computes the optimal size of a label:

@Override
protected void computeContentOptimalSize(Size size) {
        Font font = getStyle().getFont();
        int width = font.stringWidth(this.text);
        int height = font.getHeight();
        size.setSize(width, height);
}

Rendering the content of the widget

The renderContent() method is called by the MWT framework in order to render the content of the widget.

When implementing this method, the getStyle() method may be called in order to retrieve the style of the widget.

For example, the following snippet renders the content of a label:

@Override
protected void renderContent(GraphicsContext g, int contentWidth, int contentHeight) {
        Style style = getStyle();
        g.setColor(style.getColor());
        Painter.drawString(g, style.getFont(), this.text, 0, 0);
}

Handling events

When a widget is created, it is disabled and it will not receive any event. A widget may be enabled or disabled by calling setEnabled(). A common practice is to enable the widget in its constructor.

Enabled widgets can handle events by overriding handleEvent(). MicroUI event APIs may be used in order to know more information on the event, such as its type. The handleEvent() method should return whether or not the event was consumed by the widget.

For example, the following snippet prints a message when the widget receives an event:

@Override
public boolean handleEvent(int event) {
        System.out.println("Event type: " + Event.getType(event));
        return false;
}

Listening to the life-cycle hooks

Widget subclasses may override the following methods in order to allocate and free the necessary resources:

  • onAttached()
  • onDetached()
  • onLaidOut()
  • onShown()
  • onHidden()

For example, the onAttached() may be overridden to load an image:

@Override
protected void onAttached() {
        this.image = ResourceImage.loadImage(this.imagePath);
}

Likewise, the onDetached() method may be overridden to close the image:

@Override
protected void onDetached() {
        this.image.close();
}

For example, the onShown() may be overridden to start an animation:

@Override
protected void onShown() {
        Animator animator = ServiceFactory.getService(Animator.class);
        animator.startAnimation(this);
}

Likewise, the onHidden() method may be overridden to stop an animation:

@Override
protected void onHidden() {
        Animator animator = ServiceFactory.getService(Animator.class);
        animator.stopAnimation(this);
}