Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

Vaadin – Using Input Components and Forms

Save for later
  • 720 min read
  • 2013-08-01 00:00:00

(For more resources related to this topic, see here.)

The Time It application

A couple of years ago I was working with some friends on a personal Java project. We used to meet every Saturday to review what we had done before building the entire system. Let me introduce you to my friends: Susan Obstinate and Mark Nowsitall (weird last names, aren't they?).

"I've spent the entire week writing this code, but it's ready now," said Susan with an embittered tone.

"Let me see how you handled that," replied Mark suspiciously. Though they didn't seem to be, they were a couple.

So Susan proudly showed us her piece of code:

// some nasty code was here (censored for respect of the reader) public String getUglyUrl(long total) { String url = "http://localhost/app/someservice?code="; for(long i = 0; i < total; i++) { url += someTrickyMath(i); } return url; } public String someTrickyMath(long i) { // (censored) }

"We can use an int object type instead of long for the loop in your getUglyUrl method," instantly affirmed Mark.

"I don't think we need that," said Susan.

"You could also use a StringBuilder class to..." I started to say, but suddenly got interrupted by Mark.

"An int object type would improve performance a lot. The int comparisons and manipulations are faster than long ones," Mark explained.

"What if the total gets too big? We'd need a long object type then," Susan argued.

"Total has never gone beyond 10,000 and I highly doubt it will in the near future," Mark replied.

We (actually it was Mark) finally managed to convince Susan to change her code.

There are lots of situations similar to this one, more complicated, and with tons of external factors that make it hard to be 100 percent sure about which of two code strategies will work faster. Let's take advantage of this story and develop a nice Vaadin application for timing code.

Introducing: Time It! The application that will show some facts to Susan.

vaadin-using-input-components-and-forms-img-0

Time for action – separating business classes from UI classes

Vaadin is mostly about UI. Vaadin's motto thinking of U and I is not in vain. I said mostly because you can additionally find a bunch of useful add-ons to deal with server-side technologies. Even Vaadin itself ships with some data components.

Most, if not all, applications have some kind of business logic. That is, something to do with the application's data. If you are an experienced developer you will agree with me that separating business logic from UI logic makes a lot of sense. For the "Time It" application, we will use two Java packages to separate business logic from UI logic:

  1. Create a new Vaadin project named time-it using your IDE.
  2. Delete the all the generated classes. We will add our own classes in a minute.
  3. Create the following package. Don't worry about the classes right now. Just create the Java packages timeit, timeit.biz, timeit.biz.test, and timeit.ui:

    vaadin-using-input-components-and-forms-img-1

  4. Browse the book's source code and copy all the classes inside the biz package and paste them into your own biz package. Don't copy TimeItUI.java, we will work on that through the article.
  5. Create a new class with the TimeItUI name inside the ui package.
  6. Update your web.xml file to use TimeItUI as the starting application:

    <servlet> <servlet-name>Time It</servlet-name> <servlet-class>com.vaadin.server.VaadinServlet</servlet-class> <init-param> <description> Vaadin UI class to use</description> <param-name>UI</param-name> <param-value>timeit.ui.TimeItUI</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Time It</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>

  7. Let's start with an outline of our TimeItUI class. Modify your TimeItUI class to match something like this:

    public class TimeItUI extends UI { ... some variables ... @Override protected void init(VaadinRequest request) { ... } private void initCombo() { ... } private void initButton() { ... } private void initLayout() { ... } public boolean validate() { ... } public void runSelectedTest() { ... } private void showResults(Collection<String> results) { ... } }

What just happened?

Of course, the TimeItUI class won't compile. But now you have an outline with the structure of methods we will implement through the article. Just keep reading.

Most of the application is about business (the biz package) with only one class handling our UI logic. However, we will focus on the UI part. Business classes are not puzzling at all. We will use them as black boxes in our TimeItUI class (that's the reason we are just copying them).

Time for action – adding components as class members

To add UI components as class members, edit your TimeItUI class by adding these variables to it:

private static final TestSet[] testSets = new TestSet[] { new LongVsInt(), new StringVsStringBuffer(), new ShortCircuitVsNoShortCircuit() }; private VerticalLayout layout = new VerticalLayout(); private ComboBox combo = new ComboBox("Test"); private final TextField textField = new TextField("Number of iterations", "1000"); private CheckBox checkBox = new CheckBox("Keep previous results"); private Button button = new Button("Time it!"); private VerticalLayout resultsLayout = new VerticalLayout();

What just happened?

The first thing you see, testSets, is just an array of business objects, specifically, an array containing instances of TestSet (take a look at the TestSet interface in the book's source code). Think of TestSet as a single scenario from which we want to obtain timing results. For example, the LongVsInt class will run two tests: one to time a loop controlled by a long object type and another to time a loop controlled by an int object type. If you want to add some testing scenarios, all you must do is to implement the TestSet interface and add a new instance to the testSets array.

Time for action – adding some infrastructure

Edit the init method of your TimeItUI class to match the following:

@Override protected void init(VaadinRequest request) { initCombo(); initButton(); initLayout(); }

What just happened?

Here we are breaking up the functionality to initialize our UI components in a more suitable way by implementing smaller methods. Now that we have the required infrastructure, we can start adding input components.

Comboboxes

A combobox is an input component that allows users to select an option from a drop-down list. It looks like the following screenshot:

vaadin-using-input-components-and-forms-img-2

You must be thinking "yeah right, but how do you put those options in there?" This is easy:

ComboBox c = new ComboBox("Select an option"); c.addItem("Option one"); c.addItem("Option two"); c.addItem("Option three");

If you have the options in a Java Collection class, you can pass the Collection instance to the constructor like this:

ArrayList<String> options = new ArrayList<>(); options.add("Option 1"); options.add("Option 2"); options.add("Option 3"); ComboBox c = new ComboBox("Select an option", options);

The method addItem accepts an Object, so we can pass instances of any class. For example, if we had a User class we could have done this:

User user1 = new User("Jurka", "Rahikkala"); User user2 = new User("Joonas", "Lehtinen"); ComboBox c = new ComboBox("Select a user"); c.addItem(user1); c.addItem(user2);

Now, how will the ComboBox component know what to print as option captions? First, let's go back to our "Time It" application.

Time for action – adding a combobox

Implement the initCombo method of your TimeItUI class as shown in the following code snippet:

private void initCombo() { for(TestSet testSet : testSets) { combo.addItem(testSet); combo.setitemCaption(testSet, testSet.getTitle()); } combo.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { TestSet testSet = (TestSet) combo.getValue(); textField.setValue("" + testSet.getDefaultTimes()); button.setDescription(testSet.getDescription()); } }); combo.setimmediate(true); }

What just happened?

It's not that complicated. If we isolate the for portion of the previous code, we'll get this:

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime

for(TestSet testSet : testSets) { combo.addItem(testSet); combo.setitemCaption(testSet, testSet.getTitle()); }

For each TestSet instance in our array, we add a TestSet instance and then we say, "Okay, Vaadin for this testSet array I just added, please show what testSet.getTitle() returns. Thank you very much". We are adding instances of TestSet and explicitly specifying what we want to be shown for each option inside the ComboBox component.

Responding to value changes

So, we have our combo ready and showing all available tests. If you have already played with the application, you may have noted that when you select a test, the number of iterations shown in the text field and the button tooltip explaining the test are updated accordingly. Well, the rest of the initCombo method implements this functionality.

Here, We are adding a ValueChangeListener instance to execute our code when the user selects an option:

combo.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { // your code here } });

Getting and setting the value of input components

The user selects one option, the valueChange method of our anonymous listener is called, and now we can update the value in textField. That's one line of code:

textField.setValue(theValue);

Wait... how do we know what is the selected value in the combobox? If setValue is for setting the value, then getValue is for getting the value! Unbelievable! Let's get the value:

TestSet testSet = (TestSet) combo.getValue();

Now that we have the value, we can easily set the text in the textField:

textField.setValue("" + testSet.getDefaultTimes());

We've just learned something valuable (it's not wordplay): input components, they all have the getValue and setValue methods.

Tooltips

A tooltip is boxed text that appears when the user holds the mouse pointer over a UI element. The following screenshot shows a Vaadin tooltip:

vaadin-using-input-components-and-forms-img-3

Adding tooltips is a piece of cake. All we need to do is the following:

button.setDescription(testSet.getDescription());

Most UI components include this method. You can put any HTML you want to nicely format your tooltips.

Immediate mode

There is just one final line that we have not explained yet in the initCombo method:

combo.setimmediate(true);

This makes the component respond as soon as the user changes its value (and after the component loses focus). If we don't put this line, when the user changes the value, Vaadin could say "Okay, I will wait for some more events before I send that change in combo". This is not only for the ComboBox component, all input components have this method too.

Error indicators

We must provide feedback to the user when the input is incorrect. Error indicators are a way to provide such feedback.

Time for action – validating user input

We can run a TestSet instance only if the user selects one. Follow these steps to add a proper validation:

  1. Implement your initButton method to match this code:

    private void initButton() { button.addClickListener(new ClickListener() { @Override public void buttonClick(ClickEvent event) { if(isValid()) { runSelectedTest(); } } }); }

  2. Now implement your validate method. Here is how we validate:

    public boolean isValid() { combo.setComponentError(null); textField.setComponentError(null); boolean isValid = true; if(combo.getValue() == null) { combo.setComponentError( boolean isValid = true; if(combo.getValue() == null) { combo.setComponentError( new UserError("Select a test from the list.")); isValid = false; } if(textField.getValue().toString().isEmpty()) { textField.setComponentError(new UserError( "You must introduce the number of iterations to execute")); isValid = false; } return isValid; }

What just happened?

We have a button and we want to respond to click events, so we add ClickListener, using an anonymous class.

As you can see, if the isValid method returns true, we proceed to run the selected test. First two lines of the method are for clearing any error we may have added to the components in previous executions of the isValid method itself. Then, we declare a flag that will tell us whether the components have valid values or not. If the selected value in combo is null, we add an error message to the component using the following code line:

combo.setComponentError(new UserError("Select a test from the list."));

setComponentError expects an instance of ErrorMessage. UserError is an implementation of the ErrorMessage interface that allows us to show an error message on the component. Usually, the component will show an error indicator. If the user places the mouse cursor over the component, a tooltip will appear showing the error text:

vaadin-using-input-components-and-forms-img-4

A similar logic is used to show an error over textField if the users left it empty.

Layout spacing

We have our components ready. We know how they respond to events (clicks and value changes) and how they communicate. We still have to know how the tests are executed and how the results are shown. But first, let's incorporate all those components into the main layout.

Time for action – adding input component into the layout

Implement your initLayout method using the following snippet of code:

private void initLayout() { layout.setMargin(true); layout.setSpacing(true); layout.addComponent(combo); layout.addComponent(textField); layout.addComponent(checkBox); layout.addComponent(button); layout.addComponent(resultsLayout); setContent(layout); }

What just happened?

We let the layout to have an appropriate margin and spacing. This last one adds some space between components instead of having them bonded inside the layout. Following that, we add combo, textField, checkBox, button, and a VerticalLayout component to put some labels for showing the results of the test case execution. Finally, the last statement sets layout as content of the page.

Checkboxes

Everyone knows checkboxes. Have you ever accepted license agreements during software installations? Just in case, this is a checkbox:

vaadin-using-input-components-and-forms-img-5

We have already created our checkbox:

private CheckBox checkBox = new CheckBox("Keep previous results");

Removing components from layouts

Before explaining how we show the results, let's see how we can execute the selected TestSet instance.

Modal Close icon
Modal Close icon