Reputation: 3107
I have a custom component that extends a JComponent. When you click it, it catches the event with a MouseListener. Depending on the state of the component and where you click, the data stored in it updates.
How can I notify the parent container when this happens while keeping it completely self-contained?
Upvotes: 2
Views: 1486
Reputation: 285403
Myself, I would use the PropertyChangeSupport that comes with JComponent, and then fire your notify method whenever the program's state changes.
For example:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class PropChangeEg {
private static void createAndShowGui() {
final JLabel counterLabel = new JLabel(" ", SwingConstants.CENTER);
CustomComponent myCustomComponent = new CustomComponent();
myCustomComponent.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getPropertyName().equals(CustomComponent.COUNTER)) {
String text = "Counter: " + pcEvt.getNewValue();
counterLabel.setText(text);
}
}
});
JFrame frame = new JFrame("PropChangeEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(myCustomComponent, BorderLayout.CENTER);
frame.add(counterLabel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class CustomComponent extends JComponent {
public static final String COUNTER = "counter";
private int counter = 0;
public CustomComponent() {
setLayout(new FlowLayout());
add(new JButton(new AbstractAction("Increment Counter") {
@Override
public void actionPerformed(ActionEvent arg0) {
setCounter(counter + 1);
}
}));
add(new JButton(new AbstractAction("Decrement Counter") {
@Override
public void actionPerformed(ActionEvent arg0) {
setCounter(counter - 1);
}
}));
}
//@Override // not needed!!
//public void addPropertyChangeListener(PropertyChangeListener listener) {
// super.addPropertyChangeListener(listener);
//}
//@Override // not needed!!
//public void removePropertyChangeListener(PropertyChangeListener listener) {
// super.removePropertyChangeListener(listener);
//}
public void setCounter(int counter) {
int oldValue = this.counter;
int newValue = counter;
this.counter = newValue;
firePropertyChange(COUNTER, oldValue, newValue);
}
public int getCounter() {
return counter;
}
}
Regarding comments:
A ChangeListener will work fine too. 1+ to user129... but what I like about PCL is that I can specify the names of properties to listen for allowing me to listen to the changes of multiple different states and this way can create a complete View from a MVC design that is completely decoupled from the Control. So my recommendation is: if you're only listening to one state, then by all means use a ChangeListener, but if you're listening to multiple states, use a PCL.
Upvotes: 3