source bean notifies target bean with ChangeListener

T

thufir

I'm having trouble assigning ChangeListeners to a source bean and target
bean. Particularly in MySlider, how is changeListener instantiated?



thufir@arrakis:~/bcit3621$
thufir@arrakis:~/bcit3621$ cat lab2/src/a00720398/lab02/util/
ColorSelector.java

package a00720398.lab02.util;

import java.awt.Color;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ColorSelector extends javax.swing.JPanel implements
ChangeListener {

private Color color;

//private ChangeListener changeListener;
/*= new ChangeListener() {

public void stateChanged(ChangeEvent arg0) {
//throw new UnsupportedOperationException("Not supported
yet.");
color = new Color(red.getValue(), green.getValue(),
blue.getValue());
}
};*/

/** Creates new form ColorSelector */
public ColorSelector() {
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-
BEGIN:initComponents
private void initComponents() {

red = new a00720398.lab02.util.MySlider();
green = new a00720398.lab02.util.MySlider();
blue = new a00720398.lab02.util.MySlider();

setLayout(new javax.swing.BoxLayout(this,
javax.swing.BoxLayout.Y_AXIS));

/* what kind of listener do I add
* to the source bean?
* sourceBean.addChangeListener()?
*/

/*
red.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
jSlider1StateChanged(evt);
}
});
*/

red.setText("red");
add(red);

/* what kind of listener do I add
* to the source bean?
* sourceBean.addChangeListener()?
*/

green.setText("green");
add(green);

/* what kind of listener do I add
* to the source bean?
* sourceBean.addChangeListener()?
*/

blue.setText("blue");
add(blue);
}// </editor-fold>//GEN-END:initComponents


// Variables declaration - do not modify//GEN-BEGIN:variables
private a00720398.lab02.util.MySlider blue;
private a00720398.lab02.util.MySlider green;
private a00720398.lab02.util.MySlider red;
// End of variables declaration//GEN-END:variables


public Color getColor(){
return color;
}

public void stateChanged(ChangeEvent arg0) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
thufir@arrakis:~/bcit3621$
thufir@arrakis:~/bcit3621$ cat lab2/src/a00720398/lab02/util/
MySlider.java


package a00720398.lab02.util;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


public class MySlider extends javax.swing.JPanel {

private ChangeListener changeListener;
/*= new ChangeListener() {

public void stateChanged(ChangeEvent arg0) {
//throw new UnsupportedOperationException("Not supported
yet.");
changeListener.stateChanged(arg0);
}
};*/

/** Creates new form MySlider */
public MySlider() {
//changeListener = new ChangeListener();
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-
BEGIN:initComponents
private void initComponents() {
bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

jLabel1 = new javax.swing.JLabel();
jSlider1 = new javax.swing.JSlider();
jTextField1 = new javax.swing.JTextField();

jLabel1.setText("jLabel1");
add(jLabel1);

jSlider1.setMaximum(255);
jSlider1.addChangeListener(new javax.swing.event.ChangeListener()
{
public void stateChanged(javax.swing.event.ChangeEvent evt) {
jSlider1StateChanged(evt);
}
});
add(jSlider1);

org.jdesktop.beansbinding.Binding binding =
org.jdesktop.beansbinding.Bindings.createAutoBinding
(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE,
jSlider1, org.jdesktop.beansbinding.ELProperty.create("${value}"),
jTextField1, org.jdesktop.beansbinding.BeanProperty.create("text"));
bindingGroup.addBinding(binding);

add(jTextField1);

bindingGroup.bind();
}// </editor-fold>//GEN-END:initComponents

private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt)
{//GEN-FIRST:event_jSlider1StateChanged
// TODO add your handling code here:
//changeListener.stateChanged(evt);
}//GEN-LAST:event_jSlider1StateChanged


// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel jLabel1;
private javax.swing.JSlider jSlider1;
private javax.swing.JTextField jTextField1;
private org.jdesktop.beansbinding.BindingGroup bindingGroup;
// End of variables declaration//GEN-END:variables


public int getValue(){
return jSlider1.getValue();
}

public void setText(String text){
jLabel1.setText(text);
}
}
thufir@arrakis:~/bcit3621$
thufir@arrakis:~/bcit3621$ cat lab2/src/a00720398/lab02/view/
Lab02View.java

package a00720398.lab02.view;

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Lab02View extends javax.swing.JFrame implements
ChangeListener {

Color color = new Color(0,0,0);

/** Creates new form Lab02View */
public Lab02View() {
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-
BEGIN:initComponents
private void initComponents() {

jTextArea1 = new javax.swing.JTextArea();
colorSelector1 = new a00720398.lab02.util.ColorSelector();

setDefaultCloseOperation
(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new javax.swing.BoxLayout
(getContentPane(), javax.swing.BoxLayout.Y_AXIS));

jTextArea1.setColumns(20);
jTextArea1.setRows(5);
getContentPane().add(jTextArea1);
getContentPane().add(colorSelector1);

pack();
}// </editor-fold>//GEN-END:initComponents

/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
//new Lab02View().setVisible(true);
JFrame frame = new Lab02View();
frame.setLocationRelativeTo(null);
frame.setSize(600,400);
frame.setVisible(true);
}
});
}

public void stateChanged(ChangeEvent arg0) {
//throw new UnsupportedOperationException("Not supported yet.");
color = colorSelector1.getColor();
System.out.println(color);
}

// Variables declaration - do not modify//GEN-BEGIN:variables
private a00720398.lab02.util.ColorSelector colorSelector1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration//GEN-END:variables

}
thufir@arrakis:~/bcit3621$






thanks,

Thufir
 
H

hwchandler

I'm having trouble assigning ChangeListeners to a source bean and target
bean. Particularly in MySlider, how is changeListener instantiated?

thufir@arrakis:~/bcit3621$
thufir@arrakis:~/bcit3621$ cat lab2/src/a00720398/lab02/util/
ColorSelector.java

package a00720398.lab02.util;

import java.awt.Color;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class ColorSelector extends javax.swing.JPanel implements
ChangeListener {

private Color color;

//private ChangeListener changeListener;
/*= new ChangeListener() {

public void stateChanged(ChangeEvent arg0) {
//throw new UnsupportedOperationException("Not supported
yet.");
color = new Color(red.getValue(), green.getValue(),
blue.getValue());
}
};*/

/** Creates new form ColorSelector */
public ColorSelector() {
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-
BEGIN:initComponents
private void initComponents() {

red = new a00720398.lab02.util.MySlider();
green = new a00720398.lab02.util.MySlider();
blue = new a00720398.lab02.util.MySlider();

setLayout(new javax.swing.BoxLayout(this,
javax.swing.BoxLayout.Y_AXIS));

/* what kind of listener do I add
* to the source bean?
* sourceBean.addChangeListener()?
*/

/*
red.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
jSlider1StateChanged(evt);
}
});
*/

red.setText("red");
add(red);

/* what kind of listener do I add
* to the source bean?
* sourceBean.addChangeListener()?
*/

green.setText("green");
add(green);

/* what kind of listener do I add
* to the source bean?
* sourceBean.addChangeListener()?
*/

blue.setText("blue");
add(blue);
}// </editor-fold>//GEN-END:initComponents

// Variables declaration - do not modify//GEN-BEGIN:variables
private a00720398.lab02.util.MySlider blue;
private a00720398.lab02.util.MySlider green;
private a00720398.lab02.util.MySlider red;
// End of variables declaration//GEN-END:variables

public Color getColor(){
return color;
}

public void stateChanged(ChangeEvent arg0) {
throw new UnsupportedOperationException("Not supported yet.");
}}

thufir@arrakis:~/bcit3621$
thufir@arrakis:~/bcit3621$ cat lab2/src/a00720398/lab02/util/
MySlider.java

package a00720398.lab02.util;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class MySlider extends javax.swing.JPanel {

private ChangeListener changeListener;
/*= new ChangeListener() {

public void stateChanged(ChangeEvent arg0) {
//throw new UnsupportedOperationException("Not supported
yet.");
changeListener.stateChanged(arg0);
}
};*/

/** Creates new form MySlider */
public MySlider() {
//changeListener = new ChangeListener();
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-
BEGIN:initComponents
private void initComponents() {
bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

jLabel1 = new javax.swing.JLabel();
jSlider1 = new javax.swing.JSlider();
jTextField1 = new javax.swing.JTextField();

jLabel1.setText("jLabel1");
add(jLabel1);

jSlider1.setMaximum(255);
jSlider1.addChangeListener(new javax.swing.event.ChangeListener()
{
public void stateChanged(javax.swing.event.ChangeEvent evt) {
jSlider1StateChanged(evt);
}
});
add(jSlider1);

org.jdesktop.beansbinding.Binding binding =
org.jdesktop.beansbinding.Bindings.createAutoBinding
(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE,
jSlider1, org.jdesktop.beansbinding.ELProperty.create("${value}"),
jTextField1, org.jdesktop.beansbinding.BeanProperty.create("text"));
bindingGroup.addBinding(binding);

add(jTextField1);

bindingGroup.bind();
}// </editor-fold>//GEN-END:initComponents

private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt)
{//GEN-FIRST:event_jSlider1StateChanged
// TODO add your handling code here:
//changeListener.stateChanged(evt);
}//GEN-LAST:event_jSlider1StateChanged

// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel jLabel1;
private javax.swing.JSlider jSlider1;
private javax.swing.JTextField jTextField1;
private org.jdesktop.beansbinding.BindingGroup bindingGroup;
// End of variables declaration//GEN-END:variables

public int getValue(){
return jSlider1.getValue();
}

public void setText(String text){
jLabel1.setText(text);
}}

thufir@arrakis:~/bcit3621$
thufir@arrakis:~/bcit3621$ cat lab2/src/a00720398/lab02/view/
Lab02View.java

package a00720398.lab02.view;

import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Lab02View extends javax.swing.JFrame implements
ChangeListener {

Color color = new Color(0,0,0);

/** Creates new form Lab02View */
public Lab02View() {
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-
BEGIN:initComponents
private void initComponents() {

jTextArea1 = new javax.swing.JTextArea();
colorSelector1 = new a00720398.lab02.util.ColorSelector();

setDefaultCloseOperation
(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new javax.swing.BoxLayout
(getContentPane(), javax.swing.BoxLayout.Y_AXIS));

jTextArea1.setColumns(20);
jTextArea1.setRows(5);
getContentPane().add(jTextArea1);
getContentPane().add(colorSelector1);

pack();
}// </editor-fold>//GEN-END:initComponents

/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
//new Lab02View().setVisible(true);
JFrame frame = new Lab02View();
frame.setLocationRelativeTo(null);
frame.setSize(600,400);
frame.setVisible(true);
}
});
}

public void stateChanged(ChangeEvent arg0) {
//throw new UnsupportedOperationException("Not supported yet.");
color = colorSelector1.getColor();
System.out.println(color);
}

// Variables declaration - do not modify//GEN-BEGIN:variables
private a00720398.lab02.util.ColorSelector colorSelector1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration//GEN-END:variables

}

thufir@arrakis:~/bcit3621$

thanks,

Thufir

The thing to remember here is you have encapsulation taking place. In
other words, your MySlider class houses the actual components you'll
be editing. I assume you have in MySlider, a slider to change those
values, and the text area to be able to type in a value. Now, outside
of this control/component you want to watch the values change, watch
them from other code. To do this, you need to be able to see the
events taking place. There are multiple ways you can do this, but as
you have encapsulated these other JavaBeans/controls/components inside
your MySlider class you need to expose their changes some way, or
proxy them, and you need to do this with event firing mechanisms
support by Java, JavaBeans, and AWT/Swing.

I won't get into a bunch of example code, but will instead try to
first explain the principles and let you take it from there. Your best
bet however is to read the JavaBeans specification, as it tells you
exactly how to do this very thing, and you need to know how Java
handles events as well as how AWT/Swing work with events and threads.
The stuff for Java and AWT/Swing can be read by reading the JavaDocs
which come with the JDK.

First, you have your MySlider, and inside it other components. The
other components are changed, and you want to capture their values and
the fact those values have changed outside of the MySlider component/
class and inside it. i.e. From other logic you want to know when
MySlider's values change.

To do this you can attach different listeners to the slider and the
text field in your MySlider class. That means literally, inside your
MySlider class, you will create listeners of some type, state, key,
mouse, listeners or what ever, and have them listen to the different
events the sub-components of MySlider create/fire.

Those events will let you know the textfield has changed or the slider
has changed. When either ones value changes you will want to update
the other accordingly and according to the value which has been set to
always have the UI consistent with the set values, and also, you'll
need to take into account the values entered in the textfield may be
inappropriate for the slider, so if the user tries to enter something
besides a number, unless you provide conversion from other values,
that it does nothing and makes not changes.

There is another way besides doing nothing, but it is more involved,
and requires a much better understanding of how JavaBeans, AWT/Swing,
and events work, so I'll skip it for now, but just know that if you
create your own custom events you can do about anything and express
about anything you want using them. An example would be instead of
doing nothing, to have an event which has an exception attached to it
so you can tell the user exactly what they are doing wrong that is
causing no change to take place.

OK, so now you will have both the slider and the textfield
synchronizing their values. That is the first step. Next, you'll want
to have some kind of single read-only property so you can pull the
value from either the textfield or the slider, and have a single point
of entry from which to pull the MySlider value; this versus allowing
the external code to see both the textfield and the slider and having
to deal with both, and you already have this, which is good.

Next, and this is where the JavaBeans specification comes in handy
aside from using listeners as above, you need to know that the value
of MySlider has changed from external code. External code being any
code outside of the MySlider classes code. In this case, I would use
property change events or state change events. Property change, in
this case, would probably be easier.

See the class in your JavaDocs called
java.beans.PropertyChangeSupport. Add an instance to your MySlider
class, and name it pcs. You'll not add this instance through the
NetBeans UI designer, but in the editor directly. Instantiate PCS in
your constructor before the initComponents() call:
pcs = new java.beans.PropertyChangeSupport(this);

using this is important as you are telling pcs to fire events for
property changes and make this instance the source of those events.

Now, you'll want to proxy the calls to pcs.addPropertyChangeListener,
pcs.removePropertyChangeListener, and pcs.getPropertyChangeListeners,
so:
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener){
pcs.addPropertyChangeListener(propertyName, listener);
}

public void addPropertyChangeListener(PropertyChangeListener listener)
{
pcs.addPropertyChangeListener(listener);
}

public void removePropertyChangeListener(PropertyChangeListener
listener){
pcs.removePropertyChangeListener(listener);
}

public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener){
pcs.removePropertyChangeListener(propertyName, listener);
}

public PropertyChangeListener[] getPropertyChangeListeners(){
pcs.getPropertyChangeListeners();
}

public PropertyChangeListener[] getPropertyChangeListeners(String
propertyName){
pcs.getPropertyChangeListeners(propertyName);
}

//and for good measure
public void fireValuePropertyChange(){
pcs.firePropertyChangeEvent("value", oldValue,
jSlider1.getValue());
}

Now, you'll end up calling fireValuePropertyChange when ever you catch
an event which you determine has changed the value of your slider
value. You will have to keep the previous value of the slider at all
times in a new instance int variable. This will allow you to have that
old value on hand to fire property change events, and these property
change events will simplify your logic which uses the MySlider class.
All you have to do outside of the MySlider class is add a property
change listener to the MySlider instances which listens for changes in
the value property.

Now, to your question about how the event listeners are created inside
the MySlider class. Since you are using the NB UI editor, you should
be able to just add event listeners directly and visually. You can
change how event listeners are created by clicking on the top level
tree node in the "Inspector" window, so you can make it generate
anonymous, use MySlider as the implementor of the event handling
interfaces, or to use a single separate class which implements the
event listener interfaces. Regardless of how the event listener is
implemented though, you can click on a UI component then find the
"Events" tab in the "Properties" window, or right click on a UI
component and go to the events sub-menu and click on an event you
would like to listen to.

Once you have an event chosen, for instance, state change in the
slider, and a property change for the property "text" in the textfield
or a key listener to listen to typing for the textfield (easier to
make it ignore text versus numbers using this tpe of an event) then
you can add your textfield/slider synchronization logic. After your
synchronization calls you will then be able to put logic in place
which sets the oldValue and calls the method to fire the property
change event (fireValuePropertyChange).

The logic outside of MySlider will just have a property change event
hooked to it in which you'll then check to see if the changed property
is "value", and if it is then you can do what ever you want with the
new values you receive. For instance, if you get a value change in
your ColorSelector from a MySlider then you know to change the color
value of the represented RGB.

If that isn't enough info, then let me know, but that should get you
going, but what is understandable to one isn't always so for others as
it depends on perspective.

Wade
 
T

Thufir

When I break this up into smaller classes, like North and Center, it
still just seems fuzzy.

Do I want Center to implement PropertyChangeListener?

I'm not clear as to how to use

http://java.sun.com/javase/6/docs/api/java/beans/PropertyChangeSupport.html




posting from google, so it might not wrap well:

/*
* NewJFrame.java
*
* Created on August 7, 2008, 5:43 AM
*/

package a00720398.dummy.gui;

/**
*
* @author thufir
*/
public class NewJFrame extends javax.swing.JFrame {

/** Creates new form NewJFrame */
public NewJFrame() {
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {

north = new javax.swing.JPanel();
showRecordHere = new javax.swing.JTextField();
center = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
table = new javax.swing.JTable();


setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

north.setLayout(new java.awt.BorderLayout());

showRecordHere.setText("jTextField1");
north.add(showRecordHere, java.awt.BorderLayout.CENTER);

getContentPane().add(north, java.awt.BorderLayout.NORTH);

center.setLayout(new java.awt.BorderLayout());

table.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{"a0", "a1", "a2", "a3"},
{"b0", "b1", "b2", "b3"},
{null, null, null, null},
{null, null, null, null}
},
new String [] {
"Title 1", "Title 2", "Title 3", "Title 4"
}
));
table.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
tableMouseClicked(evt);
}
});
jScrollPane1.setViewportView(table);

center.add(jScrollPane1, java.awt.BorderLayout.CENTER);

getContentPane().add(center, java.awt.BorderLayout.CENTER);

pack();
}// </editor-fold>

private void tableMouseClicked(java.awt.event.MouseEvent evt) {
String string = table.getValueAt(table.getSelectedRow(),
table.getSelectedColumn()).toString();
showRecordHere.setText(string);
}

/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}

// Variables declaration - do not modify
private javax.swing.JPanel center;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JPanel north;
private javax.swing.JTextField showRecordHere;
private javax.swing.JTable table;
// End of variables declaration

}




thanks,

Thufir
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top