123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- ---
- title: Creating A Simple Component Container
- order: 70
- layout: page
- ---
-
- [[creating-a-simple-component-container]]
- = Creating a simple component container
-
- Components in Vaadin can be roughly split into two groups, `Component`{empty}s
- and `ComponentContainer`{empty}s. ComponentContainers are Components in
- themselves which can also contain other components. If you are about to
- implement a component that contains other components, then you'll get a
- headstart by extending Vaadin's `ComponentContainer`. The biggest feature
- is in transferring the list of server side components from your component
- to the client. Here's how you do it.
-
- [[server-side]]
- Server Side
- ^^^^^^^^^^^
-
- To start of we implement our server side component. For this we extend
- the ready made abstract implementation `AbstractComponentContainer`. This
- requires us to implement `addComponent(Component)`,
- `removeComponent(Component)`, `replaceComponent(Component, Component)`,
- `getComponentCount` and `getComponentIterator()`.
-
- [source,java]
- ....
- package com.example.widgetcontainer;
-
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
-
- import com.vaadin.ui.AbstractComponentContainer;
- import com.vaadin.ui.Component;
-
- public class WidgetContainer extends AbstractComponentContainer {
-
- List<Component> children = new ArrayList<Component>();
-
- @Override
- public void addComponent(Component c) {
- children.add(c);
- super.addComponent(c);
- markAsDirty();
- }
-
- @Override
- public void removeComponent(Component c) {
- children.remove(c);
- super.removeComponent(c);
- markAsDirty();
- }
-
- public void replaceComponent(Component oldComponent, Component newComponent) {
- int index = children.indexOf(oldComponent);
- if (index != -1) {
- children.remove(index);
- children.add(index, newComponent);
- fireComponentDetachEvent(oldComponent);
- fireComponentAttachEvent(newComponent);
- markAsDirty();
- }
- }
-
- public int getComponentCount() {
- return children.size();
- }
-
- public Iterator<Component> iterator() {
- return children.iterator();
- }
- }
- ....
-
- Add, remove and replace are quite straight forward. In the class we
- upkeep a list of children internally, and these three methods modify
- them. Add and remove have ready made methods in the super class for
- notifying all event handlers that the children have changed and because
- of that we should make calls to the super methods after we have updated
- the list. In `replaceComponent` we have to call
- `fireComponentDetachEvent(Component)` and
- `fireComponentAttachEvent(Component)` to manually trigger these events. In
- all three methods we should also call `markAsDirty` as a last step to
- notify the client side that the children have changed.
-
- The methods `getComponentCount()` and `iterator()` takes care of providing
- the required information that we need to the client side. Here they are
- simple delegate methods to the List's `size()` and `iterator()`.
-
- [[client-side]]
- Client Side
- ^^^^^^^^^^^
-
- Next up, we want to set up a standard GWT widget which will be our
- component container's client side widget. GWT in itself has a bunch of
- component containers in it. In GWT, these are called Panels. For this
- case I will start with a `VerticalPanel`. It is roughly the same as
- `VerticalLayout` in Vaadin. Down the road you want to edit this file to
- add features or even extend Widget to create a complete custom widget.
- For now extending `VerticalPanel` is enough and we'll use that as-is.
-
- [source,java]
- ....
- package com.example.widgetcontainer.client.ui;
-
- import com.google.gwt.user.client.ui.VerticalPanel;
-
- public class VWidgetContainer extends VerticalPanel {
- public static final String CLASSNAME = "v-widgetcontainer";
-
- public VWidgetContainer() {
- setStyleName(CLASSNAME);
- }
- }
- ....
-
- [[connector]]
- Connector
- ^^^^^^^^^
-
- Your widget's Connector will transfer the components from the server
- side as child widgets to our widget. The connector will feed the
- children to the panel trough it's standard API, namely `add(Widget)`,
- `remove(Widget)` and `clear();`
-
- Instead of going the standard route of extending
- `AbstractComponentConnector` as your connector, here we can take use of
- Vaadin's internal features and extend
- `AbstractComponentContainerConnector`. Additionally to implementing the
- `getWidget()` -method from `AbstractComponentConnector`, we also have to
- supply the class with an implementation to a method called
- `updateCaption(ComponentConnector)`. This method is there if we want the
- container to take care of the captions for all the components. We don't
- need to take care of these captions in this example so we can leave the
- implementation empty.
-
- The real benefit of extending `AbstractComponentContainerConnector` is
- that we can now extend a method called
- `onConnectorHierarchyChange(ConnectorHierarchyChangeEvent)`. This method
- will be called every time that the server side calls `markAsDirty()` if
- the component hierarchy has been changed. From within it, we can call on
- `getChildComponents` to get a list of all the child components, and
- populate our widget with those.
-
- [source,java]
- ....
- package com.example.widgetcontainer.client.ui;
-
- import java.util.List;
-
- import com.google.gwt.core.client.GWT;
- import com.google.gwt.user.client.ui.Widget;
- import com.example.widgetcontainer.WidgetContainer;
- import com.vaadin.client.ComponentConnector;
- import com.vaadin.client.ConnectorHierarchyChangeEvent;
- import com.vaadin.client.ui.AbstractComponentContainerConnector;
- import com.vaadin.client.ui.Connect;
-
- @Connect(WidgetContainer.class)
- public class WidgetContainerConnector extends
- AbstractComponentContainerConnector {
-
- @Override
- public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
- List<ComponentConnector> children = getChildComponents();
- VWidgetContainer widget = getWidget();
- widget.clear();
- for (ComponentConnector connector : children) {
- widget.add(connector.getWidget());
- }
- }
-
- @Override
- public VWidgetContainer getWidget() {
- return (VWidgetContainer) super.getWidget();
- }
-
- public void updateCaption(ComponentConnector connector) {
- }
- }
- ....
-
- This implementation removes all the component's in the widget and adds
- all that are returned from `getChildComponents`. An obvious optimization
- to these is to compare what is already in the widget and only
- add/remove/move those widgets that have changed.
-
- [[example-usage]]
- Example Usage
- ^^^^^^^^^^^^^
-
- Nothing left but to use the component! Compile the widgetset and check
- that the widgetset is in use in your web.xml. Here is a little
- stand-alone application that uses this component:
-
- [source,java]
- ....
- package com.example.widgetcontainer;
-
- import java.util.Random;
-
- import com.vaadin.terminal.WrappedRequest;
- import com.vaadin.ui.Button;
- import com.vaadin.ui.Button.ClickEvent;
- import com.vaadin.ui.Button.ClickListener;
- import com.vaadin.ui.CheckBox;
- import com.vaadin.ui.Component;
- import com.vaadin.ui.Label;
- import com.vaadin.ui.UI;
-
- public class WidgetcontainerUI extends UI {
- @Override
- public void init(VaadinRequest request) {
- VerticalLayout layout = new VerticalLayout();
- layout.setMargin(true);
- setContent(layout);
-
- Label label = new Label("Hello Vaadin user");
- layout.addComponent(label);
- final WidgetContainer widgetContainer = new WidgetContainer();
- layout.addComponent(widgetContainer);
- widgetContainer.addComponent(new Label(
- "Click the button to add components to the WidgetContainer."));
- Button button = new Button("Add more components", new ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- Random randomGenerator = new Random();
- int random = randomGenerator.nextInt(3);
- Component component;
- if (random % 3 == 0) {
- component = new Label("A new label");
- } else if (random % 3 == 1) {
- component = new Button("A button!");
- } else {
- component = new CheckBox("A textfield");
- }
- widgetContainer.addComponent(component);
- }
- });
- layout.addComponent(button);
- }
- }
- ....
|