< Index | Tutorial 5 : Dynamic Data Display

Tutorial 5 : Dynamic Data Display

Requirement

Please read the Tutorial 4 first.

Display dynamic data

In the last section of this HelloWorld Tutorial we will point out the capabilities of Kuix to dynamicaly display data. We are going to display two kind of information : a runtime value - a value read at runtime like the device platform name - and a runtime dynamic value - like a variable for instance.

In a second time, we are going to use the variable to set the value of a radio group.

Download source code Download this tutorial step.

Create a custom Data Provider

The data provider is a special object that inherits from the org.kalmeo.kuix.core.model.DataProvider class and so, has the ability to provide the Kuix Core engine with dynamic values: it works like an "unidirectional bind" between a reference (ie. an alias) an the value.

In this example, we will create a data provider for 2 dynamic data. One called platformName with the device platform name detected by Kuix, and another one with a variable called gender.

To customize our Data Provider, we need to override at least the getValue() method. In addition, we will create an accessor to set the gender value. Hereafter is the code suggested for the implementation.

public class DynamicDataProvider extends DataProvider {

    // Declare static values to identify the provided data
    private static final String PLATFORM_NAME_PROPERTY = "platformName";
    private static final String GENDER_PROPERTY = "gender";

    // create a value variable
    private String gender = "unknown";

    // create an accessor to dispatch an event when value is set
    public void setGender(String gender) {
        this.gender = gender;
        dispatchUpdateEvent(GENDER_PROPERTY);
    }

    // override the parent method to handle user defined value 
    protected Object getUserDefinedValue(String property) {

        // handle custom properties requests
        if (PLATFORM_NAME_PROPERTY.equals(property)) {
            return Kuix.getCanvas().getPlatformName();
        }
        if (GENDER_PROPERTY.equals(property)) {
            return this.gender;
        }

        // default behavior if the property has not been found
        return null;
    }

}

Create a new frame and a new screen to handle user actions and display data.

Start creating a new frame called DynamicFrame for instance. This frame implements the Frame interface.

Implement the appropriate methods so that we can display the content of an XML file called dynamic-display.xml.

public class DynamicFrame implements Frame {

    // Associate a screen to the frame
    protected Screen screen;
    // Associate our data provider to the frame
    protected DynamicDataProvider dataProvider = new DynamicDataProvider();

    public boolean onMessage(Object identifier, Object[] arguments) {
        return true;
    }

    public void onAdded() {
        // Load the content from the XML file with Kuix.loadScreen static method
        screen = Kuix.loadScreen("dynamic-display.xml", dataProvider);

        // set the application current screen  
        screen.setCurrent();
    }

    public void onRemoved() {
        // destroy the screen
        screen.cleanUp();
        // unreference the screen object to free the memory
        screen = null;
    }

}

Set the content for the new screen in the XML file

Create the XML file that will be loaded with the previous Frame (dynamic-display.xml).

<screen>
    <_title>%DYNAMIC_DISPLAY%</_title>

    <container style="layout:inlinelayout(false,fill);align:center">
        <text style="padding: 0 0 15 0">%PLATFORM_NAME(@{platformName})%</text>
        <container style="layout:gridlayout(2,1)">
            <button onAction="btn_female" shortcuts="1">%FEMALE_BTN%</button>
            <button onAction="btn_male" shortcuts="2">%MALE_BTN%</button>
        </container>
        <text>%GENDER(@{gender})%</text>
    </container>

    <screenFirstMenu onAction="back">%BACK%</screenFirstMenu>
    <screenSecondMenu>
        %MORE%
        <menuPopup>
            <menuItem onAction="about">
                %ABOUT%
            </menuItem>
            <menuItem onAction="exitConfirm">
                %EXIT%
            </menuItem>
        </menuPopup>
    </screenSecondMenu>

</screen> 

This screen contains 2 dynamic text widgets: @{platformName} and @{value}. Note the special syntax used to translate only a substring of the text widget (refer to the i18n tutorial of this tutorial for more details).

<_ATTRIBUTENAME>value</_ATTRIBUTENAME>

Implement the user actions

Open the frame created at step 1 to implement the onMessage() method. Thanks to the frame stack and the event dispatcher, "about", "exit" and "exitConfirm" actions will be handled by the HelloworldFrame. The following code implements the user actions referenced in the XML file.

public boolean onMessage(Object identifier, Object[] arguments) {
    // handle the "back" button on the screen
    if ("back".equals(identifier)) {
        // remove the current frame from the framehandler stack
        Kuix.getFrameHandler().removeFrame(this);

        // and display the main screen
        Kuix.getFrameHandler().getTopFrame().onAdded();

        // do not propagate the message through the rest of the frame stack
        return false;
    } else if ("btn_female".equals(identifier)) {
        // use the data provider to set its value
        dataProvider.setGender("F");
    } else if ("btn_male".equals(identifier)) {
        // use the data provider to set its value
        dataProvider.setGender("M");
    } 

    // let the next frames in the stack, process the message
    return true;
}

The back button returns to the main screen whereas button 1 and 2 actions change the value of the data provider.

Add the translation labels to the messages.properties

Here is the translation table for the new labels introduced in the dynamic-display.xml file that you need to add to the messages.properties file.

DYNAMIC_DISPLAY=Dynamic Display
PLATFORM_NAME=Platform name: {0}
GENDER=Gender: {0}
FEMALE_BTN=Female
MALE_BTN=Male
BACK=Back

Add action to pass from HelloWorld screen to dynamic screen

Add the folowing code into the onMessage method of the HelloWorldFrame class.

if ("showDynamic".equals(identifier)) {
    // push next frame
    Kuix.getFrameHandler().pushFrame(new DynamicFrame());
    return false;
}

Edit the HelloWorld.xml and add the folowing menuItem tag :

<menuItem onAction="showDynamic">
    %DYNAMIC_DISPLAY%
</menuItem>

Using the data provider to update a radio group value

A data provider can have many use cases as the form fill, real-time screen update, etc. The syntax is always the same as in step 3.

With a radio group for instance, we can use the value of a DataProvider to change the current selection. Look at the example below for more details:

<radioGroup onChange="">
    <_value>@{gender}</_value>
    <radioButton value="F" enabled="false">female</radioButton>
    <radioButton value="M" enabled="false">male</radioButton>
</radioGroup>

In the previous example, the value attribute of the radioGroup is binded to the data provider.

note: this example does not support data update if the user change the radio button selection. Therefore, we disabled the button so that the user cannot click directly on a button. If a bi-directional binding is needed, you can use the onChange attribute on the radioGroup to update the Data provider accordingly.

Update your CSS file with the following code to skin your radio buttons and make them visible:

radiobutton {
    bg-image: url(rb_off.png);
    bg-align: left;
    bg-repeat: 1 1;
    padding: 0 0 0 20;
    border: 1 1 1 1;
}
radiobutton:hover {
    border-color: #f19300;
}
radiobutton:selected {
    bg-image: url(rb_on.png);
}

note: do not forget to replace the image files with the appropriate ones

Screenshot

Start the midlet