2

I'm trying to build upon the answer to a question regarding SwingPropertyChangeSupport

I am attempting to modify the code given here in an answer by the very helpful, Hovercraft Full Of Eels: WindowListener does not work as expected, to allow a displayed array to be updated when changes are entered via an input dialog.

The array is updated OK but not refreshed in the GUI. I was hoping someone might be able to tell me where I've gone wrong.

here is the code:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.event.SwingPropertyChangeSupport;

public class Main {
public static void main(String[] arg) {
    GuiForUpdate display = new GuiForUpdate();
    display.setVisible(true);
}
}

class GuiForUpdate extends JFrame implements ActionListener {

/**
 * 
 */
private static final long serialVersionUID = 1L;
private FocusListener focusListener;
private String mList;
private JButton changeArrayButton;
private JTextArea codeIn, displayOutput;
private int arrayIndex;
private JPanel displayPanel;
private ArrayForUpdating arrayForUpdate = new ArrayForUpdating();

public GuiForUpdate() {
    setSize(224, 180);
    layoutLeft();
    layoutDisplay();
    layoutBottom();
}

/**
 * adds a display area for array
 */
public void layoutDisplay() {
    displayPanel = new JPanel();
    add(displayPanel, BorderLayout.CENTER);
    displayOutput = new JTextArea();
    displayPanel.add(displayOutput);
    displayOutput.addFocusListener(focusListener);

    mList = arrayForUpdate.getBoundProperty();

    arrayForUpdate.addPropertyChangeListener(new PropertyChangeListener() {

        @Override
        public void propertyChange(PropertyChangeEvent pcEvt) {
            if (pcEvt.getPropertyName().equals(
                    ArrayForUpdating.BOUND_PROPERTY)) {
                mList = (pcEvt.getNewValue().toString());
            }
        }
    });

    displayOutput.setText(mList);
}

/**
 * adds left hand side elements to left of GUI
 */
public void layoutLeft() {
    JPanel left = new JPanel();
    add(left, BorderLayout.WEST);
    codeIn = new JTextArea(2, 2);
    left.add(codeIn);
    codeIn.addFocusListener(focusListener);
}

/**
 * adds bottom elements to bottom of GUI
 */
public void layoutBottom() {
    JPanel bottom = new JPanel();
    changeArrayButton = new JButton("Modify array");
    changeArrayButton.addActionListener(this);
    bottom.add(changeArrayButton);
    add(bottom, BorderLayout.SOUTH);
}

/**
 * Process button clicks
 */
public void actionPerformed(ActionEvent ae) {

    if (ae.getSource() == changeArrayButton) {

        // first check if any code entered
        if (codeIn.getText().trim().length() != 0) {

            // call modifyMemory() method
            modifyArray();

        } else
            JOptionPane.showMessageDialog(null,
                    "Please enter something first.");
    }
}

/**
 * method to process modify array
 */
public void modifyArray() {

    // show dialog to retrieve entered address
    String addressToModify = (String) JOptionPane
            .showInputDialog("At which location?");

    // confirm if a string was entered
    if ((addressToModify != null) && (addressToModify.length() > 0)) {

        // convert to integer if decimal address entered
        arrayIndex = Integer.parseInt(addressToModify);
    }
    // pass as integer
    processInput(arrayIndex);
}

public void processInput(int a) {

    String newValue = codeIn.getText();
    arrayForUpdate.instructionsIn(newValue, a);
}
}

class ArrayForUpdating {

public static final String BOUND_PROPERTY = "bound property";
private String boundProperty = "";

private SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport(
        this);
private StringBuilder mList;
private int[] myArray;

public ArrayForUpdating() {

    myArray = new int[5];
    for (int i = 0; i < myArray.length; i++) {
        myArray[i] = 0;
    }
    setArrayyDisplayString();
}

/** 
 * method to create formatted string of array
 */
public void setArrayyDisplayString() {

    // create StringBuilder for display in memory tab
    mList = new StringBuilder();
    for (int i = 0; i < myArray.length; i++) {

        mList.append(String.format("%10s %02d %10s %02d", "Pos:   ", i,
                "Value:  ", myArray[i]));
        mList.append("\n");
    }
    setBoundProperty(mList.toString());
}

/**
 * This method takes in a string passed through from the GUI
 */
public void instructionsIn(String codeIn, int loc) {

    String code = codeIn.trim();
    int oc = Integer.parseInt(code);

    // add the data to the array
    setArrayData(loc, oc);
    loc++;
}

/**   
 * method to add data to the array
 */
public void setArrayData(int a, int memData) {
    myArray[a] = memData;

    // print array to console for checking
    for (int i = 0; i < myArray.length; i++) {
        System.out.println("location: " + i + " value: " + myArray[i]);
    }
    setArrayyDisplayString();
}

public SwingPropertyChangeSupport getSpcSupport() {
    return spcSupport;
}

public void setSpcSupport(SwingPropertyChangeSupport spcSupport) {
    this.spcSupport = spcSupport;
}

public String getBoundProperty() {
    return boundProperty;
}

public void setBoundProperty(String boundProperty) {
        String oldValue = this.boundProperty;
        System.out.println("old = " + oldValue);
        String newValue = boundProperty;
        System.out.println("new = " + newValue);
        this.boundProperty = newValue;
        spcSupport.firePropertyChange(BOUND_PROPERTY, oldValue, newValue);
    }

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

-EDIT- Hopefully removed compilation errors.

Community
  • 1
  • 1
Robert
  • 5,278
  • 43
  • 65
  • 115
  • 2
    Please edit your question to include an [sscce](http://sscce.org/) that exhibits the problem you describe. There are related examples [here](http://stackoverflow.com/a/10523401/230513) and [here](http://stackoverflow.com/a/5533581/230513). – trashgod Aug 06 '12 at 11:43
  • Apologies, I've tried to edit it down to make it simpler. – Robert Aug 06 '12 at 12:31
  • 1
    No problem, but you'll get better results if your example is _complete_, like the ones cited. – trashgod Aug 06 '12 at 17:14
  • I've just added the Main class so that's the whole thing there now. – Robert Aug 06 '12 at 17:27
  • 1
    Your code is full of compilation errors making it very difficult to help you. Consider refactoring your code so that it conforms to the [sscce](http//sscce.org) specification, and please only post valid tested code. – Hovercraft Full Of Eels Aug 06 '12 at 22:44
  • Sorry, I didn't realise that - think I've removed the compilation errors now? It runs exactly as it is for me here now. – Robert Aug 06 '12 at 23:53
  • Ah - thank you all. I think I've spotted it. Answer to follow if it works. – Robert Aug 06 '12 at 23:56
  • You did notice the 2nd argument in the constructor for SwingPropertyChangeSupport, didn't you? SwingPropertyChangeSupport(Object sourceBean, boolean notifyOnEDT) – keuleJ Oct 17 '13 at 14:42

3 Answers3

6

Here is a complete example that uses ObservedPanel in a modeless dialog.

public class PropertyChangeDialog extends JPanel {

    private JLabel label = new JLabel("null", JLabel.CENTER);
    private ObservedPanel observed = new ObservedPanel();

    public PropertyChangeDialog() {
        this.setBorder(BorderFactory.createTitledBorder("Observer"));
        this.add(label);
        observed.addPropertyChangeListener(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent e) {
                if (e.getPropertyName().equals(ObservedPanel.PHYSICIST)) {
                    String value = e.getNewValue().toString();
                    label.setText(value);
                }
            }
        });
    }

    private void display() {
        JFrame f = new JFrame("PropertyChangeDialog");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationByPlatform(true);
        f.setVisible(true);
        JDialog dialog = new JDialog(f);
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.add(observed);
        dialog.pack();
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new PropertyChangeDialog().display();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thanks and please excuse my ignorance but what is "ObservedPanel"? My IDE is complaining that it cannot be resolved to a type. – Robert Aug 06 '12 at 17:53
  • Right, it's a link to another SO answer. – trashgod Aug 06 '12 at 18:01
  • Got it now, thanks. I'm still no clearer but will keep tinkering. – Robert Aug 06 '12 at 21:23
  • 1
    @Robert I'm inferring that you're using netbeans GUI builder, aka matisse? If so, you, then "ObservedPanel" is just something which extends JPanel. Note that `PropertyChangeDialog extends JPanel` which is just how Netbeans does things. This allows you to copy/paste these classes into each other in the design view. Once these classes are compiled, then switch to design view and copy the class you want, paste where you want it to go. – Thufir Aug 15 '12 at 01:40
  • @Thufir: Neither `PropertyChangeDialog` nor `ObservedPanel` use the _Matisse_ GUI editor. Sorry if I'm missing soemthing. – trashgod Aug 15 '12 at 02:18
  • If you're not using a GUI builder of some kind, I don't understand why you're extending JPanel then. – Thufir Aug 15 '12 at 02:25
  • @Thufir: My rationale follows along these lines: I'm not overriding any methods, but extending `JPanel` is a simple way to add state and get a consistent UI delegate & `BufferStrategy`. Here's a [counter-example](http://stackoverflow.com/q/11739989/230513) that illustrates the risk and extends `JComponent` instead. A factory method is an alternative. – trashgod Aug 15 '12 at 02:42
  • Minor point, but why not change `dialog.setLocationRelativeTo(null);` to `dialog.setLocationRelativeTo(f);`? – Andrew Thompson Jan 29 '13 at 02:40
  • @AndrewThompson: My RSI was acting up and I wanted to see the both panels easily. Of course, the right answer is `setLocation(userPreference())`. :-) – trashgod Jan 29 '13 at 03:00
  • @trashgod LOL. Of course! Now ..why don't they make a constant for that value? ;) – Andrew Thompson Jan 29 '13 at 03:16
2

The code looks more or less correct (i.e. I couldn't find any obvious mistakes). You should try to run it in the debugger and ask a new question when you get stuck debugging the code.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
1

When I put displayOutput.setText(mList) within the propertyChange method, it worked:

@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
    if (pcEvt.getPropertyName().equals(
        ArrayForUpdating.BOUND_PROPERTY)) {
        mList = (pcEvt.getNewValue().toString());
        displayOutput.setText(mList);
    }
}

Thank you to everyone for your help and especially your patience.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
Robert
  • 5,278
  • 43
  • 65
  • 115