2

I am trying to develop a GUI interface with swing where components can communicate with other components via the listeners. The problems I have faced are:-

Methods


  1. Implementing listeners
  2. adding listeners with listener methods using anonymous methods
  3. adding listeners from classes which implement listeners

Problems


  1. Implementing listeners creates a mess trying to operate on objects when dealing with lots of objects
  2. same as 1 except that the constructor requires finals for anonymous methods
  3. Cant operate on objects outside of the listening class without resorting to static references.

This is really frustrating because how can I get a MouseListenerClass to draw on a JPanel that is part of a separate JFrame class without passing the JPanel to the mouseListenerClass to do operations on it.

The only method I seem to have got working is creating a Enum called MouseState, when the mouse event MousePressed is fired it sets the static Enum mouseStatus to pressed, then the JPanel paintComponent method checks the Enum mouseStatus and paints if theres a press.

This seems like the wrong way.

Is there another way?

Updated to reflect the comment by Cyrille:-

Thanks @Cyrille I had to amend your code by using casting, but the premise still works. ' public void mousePressed(MouseEvent e) {

    PaintPanel p=(PaintPanel) getTargetPanel();
    p.setMousePressed(true);
    p.setMouseCoords(e.getPoint());
}


public void mouseReleased(MouseEvent e) {
    PaintPanel p=(PaintPanel) getTargetPanel();
    p.setMousePressed(false);

}

public JPanel getTargetPanel() {
    return targetPanel;
}'
user2054388
  • 105
  • 2
  • 13

2 Answers2

2

You mouse listener should not draw on the JPanel. Instead, you should be using an MVC (Model-View-Controll) pattern.

As an example, you would set up 3 classes: the panel, the listener, and a class for holding the data (a model class). When the listener is triggred, it should edit the model. The model can then notify the panel that something has changed, and the panel can check the data in the model and draw the appropriate pixels. See http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller for more info.

BTW: this is the way most standard Swing components work. Only the very simple ones (JPanel, JTextField, etc.) allow use without, and making a complex component based on these you should use MVC

James
  • 2,483
  • 2
  • 24
  • 31
  • 1
    `JPanel` has no intrinsic model, but `JTextField` has a `Document`, as discussed [here](http://www.oracle.com/technetwork/java/architecture-142923.html#separable). See also this related [answer](http://stackoverflow.com/a/3072979/230513). – trashgod Jul 05 '13 at 18:16
1

You don't have to use static variables of any kind. You should create your subclass of JPanel to handle the painting, and provide a method in this class for the listener to communicate with it:

public class MyPanel extends JPanel {

    // status used for drawing, can be anything you want, but let's say you need to know if the mouse is pressed.
    private boolean isMousePressed;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // do your stuff here, using isMousePressed
    }

    public void setMousePressed(boolean pressed) {
        isMousePressed= pressed;
    }
}

Then your mouse listener must have a reference to a MyPanel instance and use the right method to communicate with it.

public class PaintingMouseListener implements MouseListener {

    private final JPanel targetPanel;


    public PaintingMouseListener(JPanel targetPanel) {
        this.targetPanel = targetPanel;
    }


    @Override
    public void mousePressed(MouseEvent e) {
        targetPanel.setMousePressed(true);

    }

    @Override
    public void mouseReleased(MouseEvent e) {
        targetPanel.setMousePressed(false);
    }

    // other methods of the listener
}

Then you create the mouse listener with the reference to your panel.

    MyPanel targetPanel = new MyPanel();
    // assign the mouse listener to whatever component needs it.
    component.addMouseListener(new PaintingMouseListener(targetPanel));

This is akin to an MVC solution, except that it puts the model (the variable isMousePressed) and the view (the MyPanel) together. For such a simple stuff, it's simpler to keep them together, but as things get more complicated, it's better to separate them and put the model in a class in its own right.

Cyrille Ka
  • 15,328
  • 5
  • 38
  • 58
  • Thanks @Cyrille I had to amend your code by using casting, but the premise still works. `code` public void mousePressed(MouseEvent e) { PaintPanel p=(PaintPanel) getTargetPanel(); p.setMousePressed(true); p.setMouseCoords(e.getPoint()); } public void mouseReleased(MouseEvent e) { PaintPanel p=(PaintPanel) getTargetPanel(); p.setMousePressed(false); } public JPanel getTargetPanel() { return targetPanel; }` – user2054388 Jul 05 '13 at 20:50