Meters

Meters are used to report progress to the user, generally the completion percentage of a background task such as a file load operation. An example is shown below. Clicking the Start button initiates a background task that simulates a long-running operation. Periodically, the task updates the meter to reflect its progress:

The WTKX source for the example is shown below:

<Window title="Meters" maximized="true"
    xmlns:wtkx="http://pivot.apache.org/wtkx"
    xmlns="org.apache.pivot.wtk">
    <content>
        <TablePane>
            <columns>
                <TablePane.Column width="1*"/>
            </columns>
            <rows>
                <TablePane.Row height="1*">
                    <Border>
                        <content>
                            <BoxPane styles="{horizontalAlignment:'center', verticalAlignment:'center'}">
                                <Label text="Progress:"/>
                                <Meter wtkx:id="meter" preferredWidth="200" preferredHeight="16"/>
                            </BoxPane>
                        </content>
                    </Border>
                </TablePane.Row>
                <TablePane.Row height="-1">
                    <BoxPane styles="{horizontalAlignment:'center', padding:6}">
                        <PushButton wtkx:id="progressButton" styles="{preferredAspectRatio:3}"/>
                    </BoxPane>
                </TablePane.Row>
            </rows>
        </TablePane>
    </content>
</Window>
The Java source is as follows. The main application class defines an inner class that extends the pivot.util.concurrent.Task class to simulate a background operation. This task simply sleeps for 100ms at a time and updates the meter when it wakes up to reflect the current count. Since all UI updates must be performed on the UI thread, the task queues a callback to set the meter's percent complete; a pivot.wtk.TaskAdapter is used to process the task notifications for the same reason:
package org.apache.pivot.tutorials.progress;

import org.apache.pivot.collections.Map;
import org.apache.pivot.util.concurrent.Task;
import org.apache.pivot.util.concurrent.TaskExecutionException;
import org.apache.pivot.util.concurrent.TaskListener;
import org.apache.pivot.wtk.Application;
import org.apache.pivot.wtk.ApplicationContext;
import org.apache.pivot.wtk.Button;
import org.apache.pivot.wtk.ButtonPressListener;
import org.apache.pivot.wtk.DesktopApplicationContext;
import org.apache.pivot.wtk.Display;
import org.apache.pivot.wtk.Meter;
import org.apache.pivot.wtk.PushButton;
import org.apache.pivot.wtk.TaskAdapter;
import org.apache.pivot.wtk.Window;
import org.apache.pivot.wtkx.WTKXSerializer;

public class Meters implements Application {
    public class SampleTask extends Task<Void> {
        private int percentage = 0;

        public Void execute() throws TaskExecutionException {
            // Simulate a long-running operation
            percentage = 0;

            while (percentage < 100
                && !abort) {
                try {
                    Thread.sleep(100);
                    percentage++;

                    // Update the meter on the UI thread
                    ApplicationContext.queueCallback(new Runnable() {
                        public void run() {
                            meter.setPercentage((double)percentage / 100);
                        }
                    });
                } catch(InterruptedException exception) {
                    throw new TaskExecutionException(exception);
                }
            }

            return null;
        }
    }

    private Window window = null;
    private Meter meter = null;
    private PushButton progressButton = null;

    private SampleTask sampleTask = null;

    public void startup(Display display, Map<String, String> properties)
        throws Exception {
        WTKXSerializer wtkxSerializer = new WTKXSerializer();
        window = (Window)wtkxSerializer.readObject(this, "meters.wtkx");
        meter = (Meter)wtkxSerializer.get("meter");
        progressButton = (PushButton)wtkxSerializer.get("progressButton");

        progressButton.getButtonPressListeners().add(new ButtonPressListener() {
            public void buttonPressed(Button button) {
                if (sampleTask == null) {
                    // Create and start the simulated task; wrap it in a
                    // task adapter so the result handlers are called on the
                    // UI thread
                    sampleTask = new SampleTask();
                    sampleTask.execute(new TaskAdapter<Void>(new TaskListener<Void>() {
                        public void taskExecuted(Task<Void> task) {
                            reset();
                        }

                        public void executeFailed(Task<Void> task) {
                            reset();
                        }

                        private void reset() {
                            // Reset the meter and button
                            sampleTask = null;
                            meter.setPercentage(0);
                            updateProgressButton();
                        }
                    }));
                } else {
                    // Cancel the task
                    sampleTask.abort();
                }

                updateProgressButton();
            }
        });

        updateProgressButton();

        window.open(display);
    }

    public boolean shutdown(boolean optional) {
        if (window != null) {
            window.close();
        }

        return false;
    }

    public void suspend() {
    }

    public void resume() {
    }

    private void updateProgressButton() {
        if (sampleTask == null) {
            progressButton.setButtonData("Start");
        } else {
            progressButton.setButtonData("Cancel");
        }
    }

    public static void main(String[] args) {
        DesktopApplicationContext.main(Meters.class, args);
    }
}

Next: Activity Indicators