converting code into a bean


M

Mike

hi,

I am hoping that someone can help me out with converting some code into a
bean. What I have at the moment is a custom model class which extends
Abstract SpinnerModel for a JSpinner. What I want to do is create a new
JSpinner bean which uses this custom model as default - ie so I just have to
go
TestSpinner newSpinner = new TestSpinner(val,min,max,step);
and manipulate the spinner in an ide.

I am getting lost in the bean docs on java.sun. Can someone help me out
please ?

Mike
 
Ad

Advertisements

C

Chris Smith

Mike said:
I am hoping that someone can help me out with converting some code into a
bean. What I have at the moment is a custom model class which extends
Abstract SpinnerModel for a JSpinner. What I want to do is create a new
JSpinner bean which uses this custom model as default - ie so I just have to
go
TestSpinner newSpinner = new TestSpinner(val,min,max,step);
and manipulate the spinner in an ide.

I am getting lost in the bean docs on java.sun. Can someone help me out
please ?

Just do it and call it a bean. Nothing special. JSpinner is already a
bean, and you'll inherit all of its bean properties. If you want to add
properties and such, then there is more effort.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
H

Harald Hein

Mike said:
I am hoping that someone can help me out with converting some code
into a bean. What I have at the moment is a custom model class
which extends Abstract SpinnerModel for a JSpinner. What I want
to do is create a new JSpinner bean which uses this custom model
as default - ie so I just have to go
TestSpinner newSpinner = new TestSpinner(val,min,max,step);
and manipulate the spinner in an ide.

A bean must at least have a constructor with no arguments (you can
have others, too):

public TestSpinner();

Provide set methods for the arguments if they are not already in
JSpinner.
 
M

Mike

Hi,

thanks for the tips, but I am still lost. For now I just want to create the
bean, later will want to be able to set properties such as setting the
initial values for the spinner. Here is what I have so far (hoping you can
help ...) I have not been ablke to make any progress. The jar is okay and
I can drop the spinner onto a form in a IDE (am using forte) but the spinner
model is not working.

thanks

Mike

package TestBean;

import java.beans.*;
import javax.swing.JSpinner.*;

public class MYJSpinner extends javax.swing.JSpinner {

/** Creates new MYJSpinner */
public MYJSpinner() {
MYSpinnerModel listModel = new MYSpinnerModel(1, 1, 99, 1);
javax.swing.JSpinner testSpinner = new javax.swing.JSpinner(listModel);
javax.swing.JSpinner.DefaultEditor editor =
(javax.swing.JSpinner.DefaultEditor)testSpinner.getEditor();

}
}

//end class

instantiated by

TestBean.MYJSpinner spinner1 = new TestBean.MYJSpinner();

and MYSpinnerModel (abbreviated) something like:

package TestBean;
import javax.swing.*;

public class MYSpinnerModel extends AbstractSpinnerModel
{
private int min_value, max_value, step_size, value;

public CircularSpinnerModel(int value, int min_value, int max_value, int
step_size)
{
}

public Object getNextValue()
{
return new Integer(next_value);
}

public Object getPreviousValue()
{
return new Integer(prev_value);
}

public Object getValue()
{
return new Integer(this.value);
}

public void setValue(Object value)
{
if (new_value != this.value)
{
fireStateChanged();
}
}

} // End of class
 
M

Mike

Hi,

I have got this partially working now by using:

public MYJSpinner()
{
MYSpinnerModel listModel = new MYSpinnerModel(1, 1, 99, 1);
this.setModel(listModel);
}

The JSpinner works as it should.

But what I have been unable to do is to allow the figures to be passed to
the constructor (1,1,99,1) by the properties sheet in the ide. I have set
up get and set methods and then entries appear in the propery sheet for my
spinner, but changing them does not do anything. eg

snippet:

private init=0;

public int getInit(){
return init;
}
public void setInit(int i){
init = i;
}

where I would have:
new MYSpinnerModel(init, min, max, step);

When the code runs the spinner just remains at 0. There is already a
property called 'value' for the spinner which I can't alter.

So how do I add the ability to change the values passed to the spinner model
constructor via an ide property sheet ? I'm stuck !

Mike
 
C

Chris Smith

Mike said:
snippet:

private init=0;

public int getInit(){
return init;
}
public void setInit(int i){
init = i;
}

where I would have:
new MYSpinnerModel(init, min, max, step);

When the code runs the spinner just remains at 0. There is already a
property called 'value' for the spinner which I can't alter.

So how do I add the ability to change the values passed to the spinner model
constructor via an ide property sheet ? I'm stuck !

Changing the field doesn't really do anything, since you use the field
to build a MYSpinnerModel in the constructor. Once that constructor is
finished, the fields aren't used (that I can see).

Instead of this, you need for your "setXXX" methods to actually change
the model, or even create and install a new model for the spinner.

Incidentally, I question whether it makes any sense at all to have a
bean property called "init". That implies the value that something
starts at. Unless that's a persistent property of your spinner (for
example, it returns to its initial value in response to some event?), it
doesn't make sense as a bean property. Instead, I'd use the value
property that already exists. Your model may be created with an
"initial" value, but once it exists, it just has a plain old value.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
Ad

Advertisements

R

Roedy Green

A bean must at least have a constructor with no arguments (you can
have others, too):

public TestSpinner();

It would have some methods using the getXXX setXXX isXXX naming
convention. I don't think there is a formal interface it must
implement is there?
 
R

Roedy Green

But what I have been unable to do is to allow the figures to be passed to
the constructor (1,1,99,1) by the properties sheet in the ide. I

That is what a bean is about. You don't NEED constructor parameters.
Anything you want to change has to be changeable via get/set methods.

Beans likely have to implement Serialiazable do they not so they could
have persistent state.

I always assumed that Beans were a marketing idea to make Java sound
simple, rather than something fully formalised.
 
M

Mike

Hi,

thanks for the response.
That is what a bean is about. You don't NEED constructor parameters.
Anything you want to change has to be changeable via get/set methods.

Okay, but I am not sure how to implement this. The model works with the
mimimum and maximum values etc and the way it works at the moment is to be
told what those values are when constructed.

Where do I put the get/sets ? In the bean which extends JSPinner or the
custom model. I have tried putting them in the class which extends JSPinner
and which contains the lines

MYSpinnerModel listModel = new MYSpinnerModel(1, 1, 99, 1);
this.setModel(listModel);

and by replacing the values with variable names which have a corresponding
get/set method.

Iain
 
M

Mike

Changing the field doesn't really do anything, since you use the field
to build a MYSpinnerModel in the constructor. Once that constructor is
finished, the fields aren't used (that I can see).

errm I am not sure. The custom model doesn't change the values for min, max
and increment value after it has been instantiated.
Instead of this, you need for your "setXXX" methods to actually change
the model, or even create and install a new model for the spinner.

Where, in the model class - this is not currently set as being a bean in the
manifest ?

Should MYJSpinner be instantiated with a no parameter constructor

public class MYJSpinner extends javax.swing.JSpinner implements
java.io.Serializable {
public MYJSpinner()
{
MYSpinnerModel listModel = new MYSpinnerModel();
this.setModel(listModel);
}
}

with the get/set methods being in the MYSpinnerModel class and that being
listed in the manifest as being a bean, but then when the MYJSpinner is
dragged from a palette in the ide will it allow the properties to bet set
for the model in this.setModel(listModel) ?

I am lost here !
Incidentally, I question whether it makes any sense at all to have a
bean property called "init". That implies the value that something
starts at. Unless that's a persistent property of your spinner (for
example, it returns to its initial value in response to some event?), it
doesn't make sense as a bean property. Instead, I'd use the value
property that already exists. Your model may be created with an
"initial" value, but once it exists, it just has a plain old value.

Yes, I need to rethink this part. I did the model some time ago and perhaps
need to look at this again - but I am stuck on the other bit for the moment
;-)

thanks

Mike
 
C

Chris Smith

Mike said:
errm I am not sure. The custom model doesn't change the values for min, max
and increment value after it has been instantiated.

Do you want them to be read-only properties, then? If so, don't provide
a set method for them.
Where, in the model class - this is not currently set as being a bean in the
manifest ?

??? I don't understand what you're asking. Okay, so your model class
isn't a bean... there's nothing wrong with that.
Should MYJSpinner be instantiated with a no parameter constructor

public class MYJSpinner extends javax.swing.JSpinner implements
java.io.Serializable {
public MYJSpinner()
{
MYSpinnerModel listModel = new MYSpinnerModel();
this.setModel(listModel);
}
}

with the get/set methods being in the MYSpinnerModel class and that being
listed in the manifest as being a bean, but then when the MYJSpinner is
dragged from a palette in the ide will it allow the properties to bet set
for the model in this.setModel(listModel) ?

I am lost here !

So am I. The JSpinner is the bean, not the model. Any properties you
want to change need to have mutators in the bean class (that is, the
JSpinner), not the model. Furthermore, those mutator methods need to
actually do what you advertize that they will do (the ones you posted
before didn't really do anything). That's ALL there is to it.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
Ad

Advertisements

H

Harald Hein

Roedy Green said:
I always assumed that Beans were a marketing idea to make Java sound
simple, rather than something fully formalised.

Your assumption is flawed. The formal specification is at

http://java.sun.com/products/javabeans/docs/spec.html

100+ pages bouring reading, and it exists for quite some time.

Also, beans are in widespread use. Every non-nonsens IDE and GUI
builder supports beans. Especially as a mechanism to add reusable
components to the IDE/builder. Most just don't mention that they base
this feature on beans.
 
M

Mike

Hi
Do you want them to be read-only properties, then? If so, don't provide
a set method for them.

yes, in this case they do not need to be changed dynamically, but do need to
be changed anytime the bean is droppen onto a form (ie design time only -
not run time). Okay.
So am I. The JSpinner is the bean, not the model. Any properties you
want to change need to have mutators in the bean class (that is, the
JSpinner), not the model.

Okay, that is where I have the setXXX methods.
Furthermore, those mutator methods need to
actually do what you advertize that they will do (the ones you posted
before didn't really do anything). That's ALL there is to it.

Okay, obviously I am missing something really basic here :(

The methods I have are:

public void setInit(int i){
init = i;
}

public void setMin(int mn){
min = mn;
}

public void setMax(int mx){
max = mx;
}

public void setStep(int s){
step = s;
}

I thought that by changing the values for init,min,max,step in the property
sheet would send the values to those methods (above) which would then supply
them to the model constructor when compiling - this is not working, so is
there something that I have to do in addition, to get the values I supply in
the property sheet into the variables that are used in the constructor ?

In addition, there is a value int he property sheet valled "value" which is
set to 0 and is not editable - I don't know if this has anything to do with
it.

thanks for your help so far ....

Mike
 
H

Harald Hein

Roedy Green said:
I don't think there is a formal interface it must
implement is there?

There is. I provide details in respones to another of your postings in
this thread.
 
C

Chris Smith

Mike said:
yes, in this case they do not need to be changed dynamically, but do need to
be changed anytime the bean is droppen onto a form (ie design time only -
not run time). Okay.

No, not okay. Beans are created without state, and then given their
state by property mutators after the bean has been created.
Okay, obviously I am missing something really basic here :(

The methods I have are:

public void setInit(int i){
init = i;
}

The thing you're missing is that these methods just change a variable,
AFTER that variable was already used to create the model. After the
constructor, those fields aren't used (which, incidentally, is an
indication that you are just confusing yourself by keeping them around
in the first place). As I said a while back, your methods need to
either modify the model or replace it with a new model that has those
characteristics.
I thought that by changing the values for init,min,max,step in the property
sheet would send the values to those methods (above) which would then supply
them to the model constructor when compiling - this is not working, so is
there something that I have to do in addition, to get the values I supply in
the property sheet into the variables that are used in the constructor ?

You've apparently decided that you really want to do it that way (that
is, completely build your model in the constructor for the bean), but
JavaBeans do NOT work that way. You've been told how to solve your
problem, but you're too attached to the implementation you've got.

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
J

John C. Bollinger

Mike said:
yes, in this case they do not need to be changed dynamically, but do need to
be changed anytime the bean is droppen onto a form (ie design time only -
not run time). Okay.

You seem to have a misunderstanding about the meaning and requirements
of "design time" with respect to beans. If properties need to be set a
design time (i.e. in a GUI builder or the like) then they cannot be
read-only. Bean-aware tools do not recompile your beans, nor do they
perform any kind of magic that you do not write your own code for. Such
tools instantiate your bean and set properties on the instance, using
the mutator methods that you make accessible. Thus design time _is_
runtime for the beans, albeit not for the application you are assembling.
Okay, that is where I have the setXXX methods.




Okay, obviously I am missing something really basic here :(

See above.

In addition, you seem to be missing (at least some of) the MVC
implementation that Swing employs. The JSpinner class and your custom
subclass each serve in both the view and controller roles, and the
component is completed by a separate model class. To cause the
appearance or behavior of the composite to change, you must use the
controller to change the model, with the result then reflected by the
view. (Classic MVC / model 2, except for the controller and view being
melded together.) What you are doing instead is giving the controller
its own state, and creating properties that modify that state -- but
that state isn't otherwise used anywhere.
The methods I have are:

public void setInit(int i){
init = i;
}

public void setMin(int mn){
min = mn;
}

public void setMax(int mx){
max = mx;
}

public void setStep(int s){
step = s;
}

I thought that by changing the values for init,min,max,step in the property
sheet would send the values to those methods (above) which would then supply
them to the model constructor when compiling - this is not working, so is
there something that I have to do in addition, to get the values I supply in
the property sheet into the variables that are used in the constructor ?

Compilation is already long since done when you are setting properties
on the bean via Forte. The model is constructed with the values you
pass to its constructor in your own code, not any others.
In addition, there is a value int he property sheet valled "value" which is
set to 0 and is not editable - I don't know if this has anything to do with
it.

That may be because the type of the value property is Object.
Unfortunately, JSpinner is more complicated than some Swing widgets in
that it uses a child JComponent to display and potentially change the
value property. You might or might not be able to ignore that. You
might be able to create a related, int-typed property ("intValue", for
instance) that was tied together at the back end (setting it might just
create a new Integer and pass it to setValue; reading it might then do
the reverse) and could be manipulated by Forte.

Then for the other properties it looks like you want something of the form:

public void setMin(int mn) {
MySpinnerModel mod = (MySpinnerModel) this.getModel();

mod.setMinimum(mn);
}

And likewise for the other real properties. (As I understand it, init
is not a real property, it is an initial value for the value property.)

For robustness you should also override setModel:

public void setModel(SpinnerModel model) {
if (!(model instanceof MySpinnerModel)) {
throw new IllegalArgumentException("incompatible model class");
} else {
super.setModel(model);
}
}

Otherwise you could end up with your subclass having a model of the
wrong type.


Good Luck,

John Bollinger
(e-mail address removed)
 
Ad

Advertisements

M

Mike

No, not okay. Beans are created without state, and then given their
state by property mutators after the bean has been created.

Understood (slowly, but I think I am with you)
The thing you're missing is that these methods just change a variable,
AFTER that variable was already used to create the model. After the
okay.

You've apparently decided that you really want to do it that way (that
is, completely build your model in the constructor for the bean), but
JavaBeans do NOT work that way. You've been told how to solve your
problem, but you're too attached to the implementation you've got.

Not because of anything particular reason other than I am struggling here,
but I have been trying to follow what you guys have been saying ...

Following your and John's advice it seems to be woring correctly now with
the exception of the value property (which was always available on the
properties tab). I have not been able to set the initial value - it always
just comes up as 0 and it does not appear to be editable on the properties
tab.

Mike
 
M

Mike

You seem to have a misunderstanding about the meaning and requirements
of "design time" with respect to beans. If properties need to be set a
design time (i.e. in a GUI builder or the like) then they cannot be
read-only. Bean-aware tools do not recompile your beans, nor do they
perform any kind of magic that you do not write your own code for. Such
tools instantiate your bean and set properties on the instance, using
the mutator methods that you make accessible. Thus design time _is_
runtime for the beans, albeit not for the application you are assembling.
okay.

okay. So the methods in the Spinner alter the model by calling methods in
the model ? Is that how your code in the previous post works ?
Compilation is already long since done when you are setting properties
on the bean via Forte. The model is constructed with the values you
pass to its constructor in your own code, not any others.
okay


That may be because the type of the value property is Object.
Unfortunately, JSpinner is more complicated than some Swing widgets in
that it uses a child JComponent to display and potentially change the
value property. You might or might not be able to ignore that. You
might be able to create a related, int-typed property ("intValue", for
instance) that was tied together at the back end (setting it might just
create a new Integer and pass it to setValue; reading it might then do
the reverse) and could be manipulated by Forte.

Thanks to your help and that of the various other posters help this seems
the only thing outstanding now. I tried your suggestion about creating a
new var and method which ends by calling setValue in the model. This
resolves the problem - ie the initial value of the spinner is now settable
by the property tab, but is this the right way of doing this ? The reason I
ask is that the "value" property is still available in the property tab and
of course there is the setValue method in JSpinner. Isn't this duplicating
functionality already there ? Saying that I cannot set the initial 'value'
of a standard JSpinner via the property tab - it defaults to 0. Is this
because in the latter case nothing is passed to the spinner model ? So what
is this 'value' actually supposed to be for ? I note that setValue takes an
object - is this anything to do with it ? As you can tell - I am confused
;-)

cheers

Mike
 
J

John C. Bollinger

Mike said:
okay. So the methods in the Spinner alter the model by calling methods in
the model ? Is that how your code in the previous post works ?

The methods in the controller class (the JSpinner subclass) alter the
model by invoking methods on it, yes. That is how the sample code in my
previous post worked. You should not set fields in the model directly,
because listeners will not be notified of changes made that way.
Thanks to your help and that of the various other posters help this seems
the only thing outstanding now. I tried your suggestion about creating a
new var and method which ends by calling setValue in the model. This
resolves the problem - ie the initial value of the spinner is now settable
by the property tab, but is this the right way of doing this ?

No, this is a hack that gets around a limitation in Forte. It is legal,
but not clean.
The reason I
ask is that the "value" property is still available in the property tab and
of course there is the setValue method in JSpinner. Isn't this duplicating
functionality already there ?

Yes, it is mostly a duplication of existing functionality. Its
principal purpose is to give your assembly tools a handle on the bean's
value property that they can actually use.
Saying that I cannot set the initial 'value'
of a standard JSpinner via the property tab - it defaults to 0. Is this
because in the latter case nothing is passed to the spinner model?

I'm guessing that you cannot set the initial value because Forte doesn't
know how to handle bean properties of type Object. I am furthermore
speculating that the initial value that your custom spinner is returning
is null, which might or might not indicate a programming error in your
custom model. I'll go even further out on a limb and guess that your
model is not properly notifying listeners of changes; otherwise I would
hope that the initial value displayed for the value property would track
the changes to the new intValue property. Or perhaps you didn't fully
implement my suggestion by tying the intValue property to the value
property in the back end.
So what
is this 'value' actually supposed to be for ? I note that setValue takes an
object - is this anything to do with it ? As you can tell - I am confused
;-)

In a standard JSpinner, the value property is an Object representing the
current value of the spinner -- i.e. the choice that is displayed (in
some fashion) in the UI. Another object that wants to know what value
is selected will query the bean's value property. And one that wants to
programmatically change the selection will set the value property. Your
custom component should support this, otherwise it is not correctly
implementing the superclasses' contracts. That is why I suggested that
the intValue property be tied to the value property. (And it should go
both ways, which I did not say earlier.)

You can get away without tying intValue and value together so long as
you always use the custom component in a context that knows what to do
with it, but you would not be able to plug it in to a context that only
knows about or expects standard JSpinners. If you do tie them together
then you can use your custom JSpinner anywhere (i.e. polymorphically).


John Bollinger
(e-mail address removed)
 
Ad

Advertisements

M

Mike

Hi again
The methods in the controller class (the JSpinner subclass) alter the
model by invoking methods on it, yes. That is how the sample code in my
previous post worked. You should not set fields in the model directly,
because listeners will not be notified of changes made that way.
okay

I'm guessing that you cannot set the initial value because Forte doesn't
know how to handle bean properties of type Object. I am furthermore
speculating that the initial value that your custom spinner is returning
is null,

Not sure a console print shows that all values are 0
which might or might not indicate a programming error in your
custom model. I'll go even further out on a limb and guess that your
model is not properly notifying listeners of changes; otherwise I would

It fireStateChanged(), but nothing else.
In a standard JSpinner, the value property is an Object representing the
current value of the spinner -- i.e. the choice that is displayed (in
some fashion) in the UI. Another object that wants to know what value
is selected will query the bean's value property. And one that wants to
programmatically change the selection will set the value property. Your
custom component should support this, otherwise it is not correctly
implementing the superclasses' contracts. That is why I suggested that
the intValue property be tied to the value property. (And it should go
both ways, which I did not say earlier.)

I think that it is now, but ....
You can get away without tying intValue and value together so long as
you always use the custom component in a context that knows what to do
with it, but you would not be able to plug it in to a context that only
knows about or expects standard JSpinners. If you do tie them together
then you can use your custom JSpinner anywhere (i.e. polymorphically).

now I am not so sure :)

Mike
 

Top