Adding Listeners to own components

Hey guys, i’m pretty new to Vaadin and started with vaadin 7.

my goal was, to write an own component wich beheave like an checkbox.
So i used the wiki articles of vaadin 7.

everything went finde till now. i implemented the shared state and the RPC to update the checked true:false value on server side.

it looks like that:


public class sxCheckBox extends AbstractComponent{


	private final sxCheckBoxServerRPC srpc = new sxCheckBoxServerRPC() {
		@Override
		public void clicked(final MouseEventDetails mouseDetails) {
			if (getState().enabled) {
				getState().checked = !getState().checked;
			}
		}
	};
.................
................

}

Pretty the same as in the example of the vaadin7 wiki.
Now i want to add listeners to my component like in a standard component…
so


final Button btn1 = new Button("test");
btn1.addClickListener(new ClickListener() {
			@Override
			public void buttonClick(final ClickEvent event) {
				cb.setEnabled(!cb.isEnabled());
				Notification.show("Checkbox is :"+cb.isEnabled() + " enabled");

			}
		});

and so on… no problem.
my component should be used similar but there is no methode from superclass to add listeners… sounds normal.

if i want to add a valuechangelistener to my own component, what should i do?
i don’t really know where and how to add a "addValueChangeListener(ValueChangeListener vcl) { … } " method…

may someone of you can help me?!

Ohhh … im sooo sorry

it seems that it is easier than expected…i got it with:



	HashSet<ValueChangeListener> vcl = new HashSet<ValueChangeListener>();
	public void addValueChangeListener(final ValueChangeListener vcl) {
		this.vcl.add(vcl);
	}
	public void removeValueChangeListener(final ValueChangeListener vcl) {
		this.vcl.remove(vcl);
	}

	/**
	 *
	 */
	private void updateListeners() {
		for (final ValueChangeListener listener : this.vcl) {
			listener.valueChange(new ValueChangeEvent() {

				@Override
				public Property getProperty() {
					// TODO Auto-generated method stub
					return null;
				}
			});
		}

	}

But a last anoying question :smiley: What is that Property Object and is it a bad style for returning null ?! (mhh i think yes,… returning null is always a bad idea in my thoughts)

But how can it be done better? If the “Property”-thing is fixed , is this the proper way to handle events/listeners on own components?

is there a better way?

Maybe you can implement a ValueListenerInterface which would automatically do it but i’m not sure if this works with custom components(
Information
).
What on the other hand should work would be to do some custom event handling:
You should get the click event (
In this article is an example
) then you just need a Listener interface (described
here
). When i find the time i will try to make an example and post it here if not somebody else are quicker or of course you are done before i am.

Edit:…what did i say.

The Property holds the value that is changed.
Javadoc getProperty()
. In a TextField for example it normally holds the text which has changed. For your checkbox you could return the state of the box (true or false).

Hey Marius,

thanks. i thought it would be much harder to get or my solution is so dirty that i get blamed here verywhere :wink:

Just to the property maybe i didn’t get something right:




private void updateListeners() {
		for (final ValueChangeListener listener : this.vcl) {
			listener.valueChange(new ValueChangeEvent() {
				@Override
				public Property getProperty() {
					return (Property) getState().checked;
				}
			});
		}

	}

But how can i return the changed value there?!

Okay its possible to get the value from the state object and return that, but the anon. method requires a “Property” object, so … how? ^^°

here my full component-class:


/*
 * Created: 09.08.2013
 * Copyright (c) 2005-2013 saxess ag. All rights reserved.
 */
package com.saxess.custom;

import java.util.HashSet;

import com.saxess.custom.client.sxCheckBoxServerRPC;
import com.saxess.custom.client.sxCheckBoxState;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Notification;

/**
 * TODO: Description
 *
 * @author westphal
 * @version $Id:$
 */
public class sxCheckBox extends AbstractComponent {

	HashSet<ValueChangeListener> vcl = new HashSet<ValueChangeListener>();

	private final sxCheckBoxServerRPC srpc = new sxCheckBoxServerRPC() {
		@Override
		public void clicked(final MouseEventDetails mouseDetails) {
			if (getState().enabled) {
				setChecked(!isChecked());
			}
		}
	};

	public sxCheckBox() {
		super();
		registerRpc(this.srpc);
	}

	public void setChecked(final boolean b) {
		getState().checked = b;
		Notification.show("Checked is now : " + getState().checked);
		updateListeners();

	}

	public void addValueChangeListener(final ValueChangeListener vcl) {
		this.vcl.add(vcl);
	}
	public void removeValueChangeListener(final ValueChangeListener vcl) {
		this.vcl.remove(vcl);
	}

	/**
	 *
	 */
	private void updateListeners() {
		for (final ValueChangeListener listener : this.vcl) {
			listener.valueChange(new ValueChangeEvent() {
				@Override
				public Property getProperty() {
					return null; // <------- TODO
				}
			});
		}

	}

	public boolean isChecked() {
		return getState().checked;
	}

	@Override
	public sxCheckBoxState getState() {
		return (sxCheckBoxState) super.getState();
	}

}

I don’t have a Vaadin Environment setup right now so i can’t really test it but i think you can do it like this: public Property getProperty() { Property property = new Property(); property.setValue(getState().checked); return property; }

First of all:

Thanks for your help!

and second :wink:

Property cant be instantiated. its just an interface.
And if i use the generic anonymous iner type of Property i get a bunch of functions that have to be implemented like :



			@Override
			public T getValue() {
				// TODO Auto-generated method stub
				return null;
			}

			@Override
			public void setValue(T newValue) throws com.vaadin.data.Property.ReadOnlyException {
				// TODO Auto-generated method stub
				
			}

			@Override
			public Class<? extends T> getType() {
				// TODO Auto-generated method stub
				return null;
			}

			@Override
			public boolean isReadOnly() {
				// TODO Auto-generated method stub
				return false;
			}

			@Override
			public void setReadOnly(boolean newStatus) {
				// TODO Auto-generated method stub
				
			}

It seems like also the wrong way… ^^°

Oh i think you actually don’t have to instantiate property. Property property; property.setValue(...); but if i’m wrong it’s going to throw a NullPointerException.

mhh , eclipse / the lexer wont let it uninstantiated.

i mean, it works already nevertheless i return null as “Property”. I also didn’t get any error… but mhh there is sure a more smart way i think :smiley:

MAy i should have a look on some addons and look for a component which is able to add some listeners :wink:

Now i have my Environment setup:
If you just want to have a custom listener whose event you can call from your server-side you can do something similar to this:
MyComponent.java:[code]
private MyComponentServerRpc rpc = new MyComponentServerRpc() {
private static final long serialVersionUID = 1L;
@Override
public void clicked(MouseEventDetails mouseDetails) {
Iterator i = _listeners.iterator();
while(i.hasNext()) {
Object id = i.next();
((ClickingListener) id).OnClick();
}
}
};

      private List<ClickingListener> _listeners = new ArrayList<ClickingListener>();

  public synchronized void addEventListener(ClickingListener clickListener){
	  _listeners.add(clickListener);
  }
  
  public synchronized void removeEventListener(ClickingListener clicklistener){
	  _listeners.remove(clicklistener);
  }

public interface ClickingListener extends Serializable{
	public void OnClick();
}

[/code]In my case it gets triggered by an rpc.

Usage:[code]
MyComponent testcomp = new MyComponent();
testcomp.addEventListener(new ClickingListener() {

		@Override
		public void OnClick() {
			System.out.println("Clicked");
		}
	});

[/code]I would also post the rpc but my component crashed my app because of some other change :slight_smile:

Hello,

Built-in Vaadin field components think of values in terms of Properties. Properties are a part of the Vaadin data model library, used to bind data from different sources, such as databases, to Vaadin components.

Property is basically just something that has a value. If you take a look at Vaadin’s own components, you’ll notice that all field components actually
implement the Property interface themselves
(via extending AbstractField). Then, they simply return themselves in the getProperty() method - please see Field.ValueChangeEvent.

If you want your own checkbox component to interact nicely with the rest of Vaadin, you should consider implementing Field yourself (you’ll want to do this by extending AbstractField - that way you get lots of handy stuff free, including value change listeners).

Alternatively, you could implement Property yourself; yet another way would be to implement your own ValueChangeListener and ValueChangeEvent interfaces that don’t depend on Properties. These ways, however, would mean lots of reinventing the wheel to create something that does not behave the same way as other Vaadin fields. Of course, it might be a useful learning experience.