First things first -- I had posted a question earlier wherein i had asked for help as to why my code was not working and this question is acting upon the advice i got in tha
I'm really lost (from your last three question),
may be, could we imagine that you have got three separated Models
for one GUI, in this case doesn't important if you want to change number of elements in the GUI, or change properties for one JComponent
,
output from PropertyChangeListener
quite guarantee that output could be done on EDT
import java.awt.BorderLayout;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.LinkedList;
import java.util.Queue;
import javax.swing.*;
public class MVC_ProgressBarThread {
private MVC_ProgressBarThread() {
MVC_View view = new MVC_View();
MVC_Model model = new MVC_Model();
MVC_Control control = new MVC_Control(view, model);
view.setControl(control);
JFrame frame = new JFrame("MVC_ProgressBarThread");
frame.getContentPane().add(view);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
MVC_ProgressBarThread mVC_ProgressBarThread = new MVC_ProgressBarThread();
}
});
}
}
class MVC_View extends JPanel {
private static final long serialVersionUID = 1L;
private MVC_Control control;
private JProgressBar progressBar = new JProgressBar();
private JButton startActionButton = new JButton("Press Me and Run this Madness");
private JLabel myLabel = new JLabel("Nothing Special");
public MVC_View() {
startActionButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
buttonActionPerformed();
}
});
JPanel buttonPanel = new JPanel();
startActionButton.setFocusPainted(false);
buttonPanel.add(startActionButton);
setLayout(new BorderLayout(10, 10));
add(buttonPanel, BorderLayout.NORTH);
progressBar.setStringPainted(true);
add(progressBar, BorderLayout.CENTER);
myLabel.setIcon(UIManager.getIcon("OptionPane.questionIcon"));
myLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
add(myLabel, BorderLayout.SOUTH);
}
public void setControl(MVC_Control control) {
this.control = control;
}
private void buttonActionPerformed() {
if (control != null) {
control.doButtonAction();
}
}
public void setProgress(int progress) {
progressBar.setValue(progress);
}
public void setProgressLabel(String label) {
progressBar.setString(label);
}
public void setIconLabel(Icon icon) {
myLabel.setIcon(icon);
}
public void start() {
startActionButton.setEnabled(false);
}
public void done() {
startActionButton.setEnabled(true);
setProgress(100);
setProgressLabel(" Done !!! ");
setIconLabel(null);
}
}
class MVC_Control {
private MVC_View view;
private MVC_Model model;
public MVC_Control(final MVC_View view, final MVC_Model model) {
this.view = view;
this.model = model;
model.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pce) {
if (MVC_Model.PROGRESS.equals(pce.getPropertyName())) {
view.setProgress((Integer) pce.getNewValue());
}
if (MVC_Model.PROGRESS1.equals(pce.getPropertyName())) {
view.setProgressLabel((String) pce.getNewValue());
}
if (MVC_Model.PROGRESS2.equals(pce.getPropertyName())) {
view.setIconLabel((Icon) pce.getNewValue());
}
}
});
}
public void doButtonAction() {
view.start();
SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
model.reset();
model.startSearch();
return null;
}
@Override
protected void done() {
view.done();
}
};
swingworker.execute();
}
}
class MVC_Model {
public static final String PROGRESS = "progress";
public static final String PROGRESS1 = "progress1";
public static final String PROGRESS2 = "progress2";
private static final int MAX = 11;
private static final long SLEEP_DELAY = 1000;
private int progress = 0;
private String label = "Start";
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private PropertyChangeSupport pcs1 = new PropertyChangeSupport(this);
private PropertyChangeSupport pcs2 = new PropertyChangeSupport(this);
private final String[] petStrings = {"Bird", "Cat", "Dog",
"Rabbit", "Pig", "Fish", "Horse", "Cow", "Bee", "Skunk"};
private int index = 1;
private Queue<Icon> iconQueue = new LinkedList<Icon>();
private Icon icon = (UIManager.getIcon("OptionPane.questionIcon"));
public void setProgress(int progress) {
int oldProgress = this.progress;
this.progress = progress;
PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS,
oldProgress, progress);
pcs.firePropertyChange(evt);
}
public void setProgressLabel(String label) {
String oldString = this.label;
this.label = label;
PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS1,
oldString, label);
pcs1.firePropertyChange(evt);
}
public void setIconLabel(Icon icon) {
Icon oldIcon = this.icon;
this.icon = icon;
PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS2,
oldIcon, icon);
pcs2.firePropertyChange(evt);
}
public void reset() {
setProgress(0);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
pcs1.addPropertyChangeListener(listener);
pcs2.addPropertyChangeListener(listener);
}
public void startSearch() {
iconQueue.add(UIManager.getIcon("OptionPane.errorIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.informationIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.warningIcon"));
iconQueue.add(UIManager.getIcon("OptionPane.questionIcon"));
for (int i = 0; i < MAX; i++) {
int newValue = (100 * i) / MAX;
setProgress(newValue);
setProgressLabel(petStrings[index]);
index = (index + 1) % petStrings.length;
setIconLabel(nextIcon());
try {
Thread.sleep(SLEEP_DELAY);
} catch (InterruptedException e) {
}
}
}
private Icon nextIcon() {
Icon icon1 = iconQueue.peek();
iconQueue.add(iconQueue.remove());
return icon1;
}
}
Your problem has been mentioned before as has its solution. You must actually add or remove the component to your observer panel from within the PropertyChangeListener. Calling revalidate()
and repaint()
will not magically add or remove components unless you explicitly do this before these methods are called.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.IndexedPropertyChangeEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class ListenToTest {
public static final String[] ITEMS = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"};
private JPanel mainPanel = new JPanel();
private ObserverPanel observerPanel = new ObserverPanel();
private ListenToModel model = new ListenToModel();
public ListenToTest() {
observerPanel.setModel(model);
for (String item : ITEMS) {
model.addItem(item);
}
JPanel btnPanel = new JPanel();
btnPanel.add(new JButton(new AddAction("Add")));
btnPanel.add(new JButton(new RemoveAction("Remove")));
mainPanel.setLayout(new BorderLayout());
mainPanel.add(new JScrollPane(observerPanel.getMainComponent()));
mainPanel.add(btnPanel, BorderLayout.PAGE_END);
}
public JComponent getMainComponent() {
return mainPanel;
}
private class AddAction extends AbstractAction {
public AddAction(String title) {
super(title);
}
@Override
public void actionPerformed(ActionEvent arg0) {
String text = JOptionPane.showInputDialog(mainPanel, "Enter a String");
if (text != null) {
model.addItem(text);
}
}
}
private class RemoveAction extends AbstractAction {
public RemoveAction(String title) {
super(title);
}
@Override
public void actionPerformed(ActionEvent arg0) {
int index = observerPanel.getSelectedIndex();
if (index >= 0) {
model.removeItem(index);
}
}
}
private static void createAndShowGui() {
ListenToTest mainPanel = new ListenToTest();
JFrame frame = new JFrame("ListenToModelTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel.getMainComponent());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ObserverPanel {
public static final Font LABEL_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 18);
protected static final Color SELECTED_COLOR = new Color(150, 150, 255);
private JPanel mainPanel = new JPanel();
private ListenToModel model;
private GridLayout gridLayout = new GridLayout(0, 1);
private int selectedIndex = -1;
public ObserverPanel() {
mainPanel.setLayout(gridLayout);
mainPanel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
Component[] components = mainPanel.getComponents();
for (int i = 0; i < components.length; i++) {
if (mainPanel.getComponentAt(p).equals(components[i])) {
selectedIndex = i;
components[i].setBackground(SELECTED_COLOR);
} else {
components[i].setBackground(null);
}
}
}
});
}
public int getSelectedIndex() {
return selectedIndex;
}
public void setModel(ListenToModel model) {
this.model = model;
model.addPropertyChangeListener(new ObserverPanelListener());
}
public JComponent getMainComponent() {
return mainPanel;
}
private class ObserverPanelListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(ListenToModel.ADD)) {
JLabel label = createLabel(evt);
for (Component comp : mainPanel.getComponents()) {
comp.setBackground(null);
}
int index = ((IndexedPropertyChangeEvent)evt).getIndex();
mainPanel.add(label, index);
label.setBackground(SELECTED_COLOR);
selectedIndex = index;
} else if (evt.getPropertyName().equals(ListenToModel.REMOVE)) {
int index = ((IndexedPropertyChangeEvent)evt).getIndex();
mainPanel.remove(index);
for (Component comp : mainPanel.getComponents()) {
comp.setBackground(null);
}
selectedIndex = -1;
} else if (evt.getPropertyName().equals(ListenToModel.REMOVE_ALL)) {
mainPanel.removeAll();
selectedIndex = -1;
}
mainPanel.revalidate();
mainPanel.repaint();
}
private JLabel createLabel(PropertyChangeEvent evt) {
String newValue = evt.getNewValue().toString();
JLabel label = new JLabel(newValue);
label.setFont(LABEL_FONT);
int eb = 20;
label.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.blue),
BorderFactory.createEmptyBorder(eb , eb, eb, eb)));
label.setFocusable(true);
label.setOpaque(true);
return label;
}
}
}
class ListenToModel implements Iterable<String> {
public static final String ADD = "add";
public static final String REMOVE = "remove";
public static final String REMOVE_ALL = "remove all";
private SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport(
this);
private List<String> modelNucleus = new ArrayList<String>();
public void addItem(String item) {
modelNucleus.add(item);
spcSupport.fireIndexedPropertyChange(ADD, modelNucleus.size() - 1, null,
item);
}
public void addItem(int index, String item) {
if (index < 0 || index > modelNucleus.size()) {
// TODO: throw an exception
} else {
modelNucleus.add(index, item);
spcSupport.fireIndexedPropertyChange(REMOVE, index, null, item);
}
}
public void removeItem(int index) {
if (index < 0 || index >= modelNucleus.size()) {
// TODO: throw an exception
} else {
String oldValue = modelNucleus.remove(index);
spcSupport.fireIndexedPropertyChange(REMOVE, index, oldValue, null);
}
}
public void removeAll() {
modelNucleus.clear();
spcSupport.firePropertyChange(REMOVE_ALL, null, null);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
spcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
spcSupport.removePropertyChangeListener(listener);
}
@Override
public Iterator<String> iterator() {
return modelNucleus.iterator();
}
}
Please verify that the PropertyChangeEvent does not fire. If it does fire, but the repaint does not happen, it might help to postpone the repaint a bit like this:
//change this
button.repaint();
// to this
SwingUtilties.invokeLater(new Runnable() { public void run() { button.repaint(); }});
If the change event does not fire - disregard all after 'Please' ;)