aboutsummaryrefslogtreecommitdiffstats
path: root/documentation/components/components-progressbar.asciidoc
blob: fa443d1b47056dcc7d52e3d68039c586d129716c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
---
title: ProgressBar
order: 27
layout: page
---

[[components.progressbar]]
= [classname]#ProgressBar#

ifdef::web[]
[.sampler]
image:{live-demo-image}[alt="Live Demo", link="http://demo.vaadin.com/sampler/#ui/interaction/progress-bar"]
endif::web[]

The [classname]#ProgressBar# component allows visualizing progress of a task.
The progress is specified as a floating-point value between 0.0 and 1.0.

[[figure.components.progressbar.basic]]
.The [classname]#ProgressBar# component
image::img/progressbar-basic.png[width=30%, scaledwidth=70%]

To display upload progress with the [classname]#Upload# component, you can
update the progress bar in a [interfacename]#ProgressListener#.

When the position of a progress bar is done in a background thread, the change
is not shown in the browser immediately. You need to use either polling or
server push to update the browser. You can enable polling with
[methodname]#setPollInterval()# in the current UI instance. See
<<dummy/../../../framework/advanced/advanced-push#advanced.push,"Server Push">>
for instructions about using server push. Whichever method you use to update the
UI, it is important to lock the user session by modifying the progress bar value
inside [methodname]#access()# call, as illustrated in the following example and
described in
<<dummy/../../../framework/advanced/advanced-push#advanced.push.running,"Accessing UI from Another Thread">>.

[source, java]
----
ProgressBar bar = new ProgressBar(0.0f);
layout.addComponent(bar);

layout.addComponent(new Button("Increase", click -> {
    float current = bar.getValue();
    if (current < 1.0f)
        bar.setValue(current + 0.10f);
}));
----

[[components.progressbar.indeterminate]]
== Indeterminate Mode

In the indeterminate mode, a non-progressive indicator is displayed
continuously. The indeterminate indicator is a circular wheel in the built-in
themes. The progress value has no meaning in the indeterminate mode.

[source, java]
----
ProgressBar bar = new ProgressBar();
bar.setIndeterminate(true);
----

[[figure.components.progressbar.indeterminate]]
.Indeterminate progress bar
image::img/progressbar-indeterminate.png[width=15%, scaledwidth=40%]

ifdef::web[]
[[components.progressbar.thread]]
== Doing Heavy Computation

The progress bar is typically used to display the progress of a heavy
server-side computation task, often running in a background thread. The UI,
including the progress bar, can be updated either with polling or by using
server push. When doing so, you must ensure thread-safety, most easily by
updating the UI inside a [methodname]#UI.access()# call in a
[interfacename]#Runnable#, as described in
<<dummy/../../../framework/advanced/advanced-push#advanced.push.running,"Accessing
UI from Another Thread">>.

In the following example, we create a thread in the server to do some "heavy
work" and use polling to update the UI. All the thread needs to do is to set the
value of the progress bar with [methodname]#setValue()# and the current progress
is displayed automatically when the browser polls the server.


[source, java]
----
HorizontalLayout barbar = new HorizontalLayout();
layout.addComponent(barbar);

// Create the bar, disabled until progress is started
final ProgressBar progress = new ProgressBar(new Float(0.0));
progress.setEnabled(false);
barbar.addComponent(progress);

final Label status = new Label("not running");
barbar.addComponent(status);

// A button to start progress
final Button button = new Button("Click to start");
layout.addComponent(button);

// A thread to do some work
class WorkThread extends Thread {
    // Volatile because read in another thread in access()
    volatile double current = 0.0;

    @Override
    public void run() {
        // Count up until 1.0 is reached
        while (current < 1.0) {
            current += 0.01;

            // Do some "heavy work"
            try {
                sleep(50); // Sleep for 50 milliseconds
            } catch (InterruptedException e) {}

            // Update the UI thread-safely
            UI.getCurrent().access(new Runnable() {
                @Override
                public void run() {
                    progress.setValue(new Float(current));
                    if (current < 1.0)
                        status.setValue("" +
                            ((int)(current*100)) + "% done");
                    else
                        status.setValue("all done");
                }
            });
        }

        // Show the "all done" for a while
        try {
            sleep(2000); // Sleep for 2 seconds
        } catch (InterruptedException e) {}

        // Update the UI thread-safely
        UI.getCurrent().access(new Runnable() {
            @Override
            public void run() {
                // Restore the state to initial
                progress.setValue(new Float(0.0));
                progress.setEnabled(false);

                // Stop polling
                UI.getCurrent().setPollInterval(-1);

                button.setEnabled(true);
                status.setValue("not running");
            }
        });
    }
}

// Clicking the button creates and runs a work thread
button.addClickListener(new Button.ClickListener() {
    public void buttonClick(ClickEvent event) {
        final WorkThread thread = new WorkThread();
        thread.start();

        // Enable polling and set frequency to 0.5 seconds
        UI.getCurrent().setPollInterval(500);

        // Disable the button until the work is done
        progress.setEnabled(true);
        button.setEnabled(false);

        status.setValue("running...");
    }
});
----

The example is illustrated in <<figure.components.progressbar.thread>>.

[[figure.components.progressbar.thread]]
.Doing heavy work
image::img/progressbar-thread.png[width=40%, scaledwidth=70%]

endif::web[]

[[components.progressbar.css]]
== CSS Style Rules


[source, css]
----
.v-progressbar, v-progressbar-indeterminate {}
  .v-progressbar-wrapper {}
    .v-progressbar-indicator {}
----

The progress bar has a [literal]#++v-progressbar++# base style.
The progress is an element with [literal]#++v-progressbar-indicator++# style inside the wrapper, and therefore displayed on top of it.
When the progress element grows, it covers more and more of the animated background.

The progress bar can be animated (some themes use that).
Animation is done in the element with the [literal]#v-progressbar-wrapper# style, by having an animated GIF as the background image.

In the indeterminate mode, the top element also has the
[literal]#++v-progressbar-indeterminate++# style.
The built-in themes simply display the animated GIF in the top element and have the inner elements disabled.