Creating GWT Component

Creating Custom WidgetSet

Jmix framework provides a ready-compiled widgetset in the jmix-ui-widgets-compiled artifact.

To create a custom widgetset in the project, you need to:

  1. Remove implementation 'io.jmix.ui:jmix-ui-widgets-compiled' dependency.

  2. Add dependencies to your build.gradle:

    implementation 'io.jmix.ui:jmix-ui-widgets' (1)
    widgets 'io.jmix.ui:jmix-ui-widgets'
    1 Required only for developing custom client-side components.
  3. Add the compileWidgets task (change paths according to your application base package):

    compileWidgets {
        generate "ui.ex1.widgets.CustomWidgetSet"
        includePaths('**/io/jmix/**/widget/**', '**/ui/ex1/widgets/**')
    }

    The excludePaths and includePaths parameters for the compileWidgets task are useful if you don’t want to compile a widgetset in case, for example, some screen is changed.

    The excludePaths parameter is used to exclude some paths or files from the widgetset compilation. See the example:

    compileWidgets {
        generate 'com.company.demo.widgets.CustomWidgetSet'
        excludePaths('**/com/company/demo/**')
    }

    Thus, changes in the com.company.demo package do not trigger the widgetset compilation.

    The includePaths parameter is used to include some paths or files to the widgetset compilation.

    See the example:

    compileWidgets {
        generate 'com.company.demo.widgets.CustomWidgetSet'
        includePaths('**/io/jmix/**/widget/**', '**/com/company/demo/widgets/**')
    }

    Thus, changes in the com.company.demo.widgets package and in any widget package (including sub-packages) under the io.jmix package trigger the widgetset compilation. Other changes, for example, in screen controllers or XML descriptors do not trigger such compilation. If you see unexpected re-compilation, check the particular reason (execute compileWidgets with the --info parameter).

    The excludePaths and includePaths parameters accept the list of string patterns.

    Patterns may include:

    • * to match any number of characters.

    • ? to match any single character.

    • ** to match any number of directories or files.

    Either '/' or '\' may be used in a pattern to separate directories.

    For example, includePaths('**/com/company/demo/widgets/**') includes all files in the com/company/demo/widgets directory including subdirectories.

  4. Add the jmix.ui.widget-set property to your application.properties file (adjust location according to the compileWidgets task above):

    jmix.ui.widget-set=ui.ex1.widgets.CustomWidgetSet

Widgetsets are compiled by the WidgetsCompile task named compileWidgets. It is automatically created when using the Jmix plugin.

The compiled widgetset is placed in the build/widgets directory and will be included in the JAR/WAR artifact of the project.

Creating ColorButton GWT Component

In this section, we will create a custom ColorButton component. This component is directly inherited from the JmixButton component.

Custom UI components (that is, components directly inherited from Vaadin components) should be placed in the widgets subpackage, for example, com.company.sample.widgets. Clients-side components (connectors and widgets), as well as classes used for server-side and client-side communication, such as RPC and State, should be placed in the widgets.client subpackage, for example com.company.sample.widgets.client. More information about client-server integration can be found in the Vaadin documentation.

Creating Component State Class

Create ColorButtonState.java within the widgets.client package.

The ColorButtonState state class defines what data is sent between the client and the server. It contains public fields that are automatically serialized on the server-side and deserialized on the client.

ColorButtonState.java
public class ColorButtonState extends JmixButtonState {

    public String color = "";
}

Creating Vaadin Component Class

ColorButton is a Vaadin component class. It can define an API for the server code, accessor methods, event listeners, and data sources connection. Developers use the methods of this class in the application code.

Create ColorButton.java within the widgets package:

ColorButton.java
public class ColorButton extends JmixButton {

    @Override
    protected ColorButtonState getState() {
        return (ColorButtonState) super.getState();
    }

    @Override
    protected ColorButtonState getState(boolean markAsDirty) {
        return (ColorButtonState) super.getState(markAsDirty);
    }

    public String getColor() {
        return getState(false).color;
    }

    public void setColor(String color) {
        if (!Objects.equals(getState(false).color, color)) {
            getState().color = color;
        }
    }
}

Creating Connector

Create ColorButtonConnector.java within the widgets.client package.

The ColorButtonConnector connector links client code with the server.

ColorButtonConnector.java
@Connect(ColorButton.class) (1)
public class ColorButtonConnector extends JmixButtonConnector {

    @Override
    public ColorButtonState getState() {
        return (ColorButtonState) super.getState(); (2)
    }

    @Override
    public void onStateChanged(StateChangeEvent event) { (3)
        super.onStateChanged(event);

        if (event.hasPropertyChanged("color")) { (4)
            Style style = getWidget().getElement().getStyle();
            style.setBackgroundColor(getState().color);
            style.setBackgroundImage("none");
        }
    }
}
1 With this annotation the ColorButtonConnector connector is marked to have a server-side counterpart. The value of the annotation is ColorButton - the class of server-side implementation .
2 Returns the ColorButtonState object for this connector.
3 Reacts on server state change.
4 Refreshes the widget’s style if the value on server has changed.

Using ColorButton

To demonstrate how the component works, let’s create a new color-button-screen screen.

Open the ColorButtonScreen.java screen controller and add the code that puts the component to the screen:

ColorButtonScreen.java
@UiController("sample_ColorButtonScreen")
@UiDescriptor("color-button-screen.xml")
public class ColorButtonScreen extends Screen {
    @Subscribe
    protected void onInit(InitEvent event) {
        ColorButton button = new ColorButton(); (1)
        button.setCaption("Button");
        button.setColor("#AFEEEE");
        getWindow().unwrap(Layout.class).addComponent(button); (2)
    }
}
1 Initializes a color button component instance.
2 Retrieves a link to the Vaadin container using the unwrap() method, and adds the new component to it.

The picture below shows the project structure:

project structure

Start the application and see the result:

color button