0

I have separate class to handle mouse listener. But it not working when I use it from another class and I don't know yet how to solve this. Here my Handler class:

some import stuff

public class Handler implements MouseListener, MouseMotionListener {
private final Canvas canvas;

public Handler(Canvas targetCanvas) {
    this.canvas = targetCanvas;
}

// recasting exception
public Canvas getTargetCanvas() {
    return canvas;
}
...
...
@Override
public void mouseDragged(MouseEvent e) {
    // recasting exception
    DrawingCanvas dC = (DrawingCanvas) getTargetCanvas();
    dC.setMouseDragged(true);
}

@Override
public void mouseMoved(MouseEvent e) {
    // recasting exception
    DrawingCanvas dCanvas = (DrawingCanvas) getTargetCanvas();
    dCanvas.setMouseClicked(true);
    dCanvas.setMouseCoordinates(e.getPoint());
}
}

DrawingCanvas class:

some import stuff

public class DrawingCanvas extends Canvas {
private boolean isMouseDragged, isMouseMoved;
private Point mouseCoordinates;

public DrawingCanvas() {
    this.setPreferredSize(new Dimension(790, 500));
    this.setBackground(Color.WHITE);
}

public Point getMouseCoordinates() {
    return mouseCoordinates;
}

public boolean isIsMouseDragged() {
    return isMouseDragged;
}

public boolean isIsMouseMoved() {
    return isMouseMoved;
}
...
...
public void setMouseDragged(boolean dragged) {
    isMouseDragged = dragged;
}

public void setMouseMoved(boolean moved) {
    isMouseMoved = moved;
}

public void setMouseCoordinates(Point coordinates) {
    mouseCoordinates = coordinates;
}
}

StatusBar class:

some import stuff

public class StatusBar extends JPanel {
private JLabel statusBar;

public StatusBar() {
    statusBar = new JLabel();

    this.setPreferredSize(new Dimension(500, 30));
    this.setBackground(new Color(242,241,240));
    this.add(statusBar, new BorderLayout(5,0));

}

public JLabel getStatusBar() {
    return statusBar;
}

public void setStatusBar(JLabel statusBar) {
    this.statusBar = statusBar;
}
}

And MouseEventGUI class:

some import stuff

public class MouseEventGUI extends JFrame {
private DrawingCanvas drawingCanvas;
private StatusBar statusBar;
private MenuBar menuBar;

public MouseEventGUI() {
    super("Learn Mouse Event");

    drawingCanvas = new DrawingCanvas();
    statusBar = new StatusBar();
    menuBar = new MenuBar();

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setPreferredSize(new Dimension(750, 560));

    this.add(menuBar, BorderLayout.NORTH);
    this.add(drawingCanvas, BorderLayout.CENTER);       
    this.add(statusBar, BorderLayout.SOUTH);
    this.addMouseListener(new Handler(drawingCanvas));
    this.addMouseMotionListener(new Handler(drawingCanvas));

    if(drawingCanvas.isIsMouseMoved()){
        statusBar.getStatusBar().setText(String.format("%d, %d", 
                drawingCanvas.getMouseCoordinates().x, 
                drawingCanvas.getMouseCoordinates().y));
    } else {
        statusBar.getStatusBar().setText("Mouse is not listened.");
    }    
}
}

when i run the program, in status bar show "Mouse is not listened" (see in MouseEventGUI class) that I wish it show the coordinates of mouse cursor if I moved it in canvas.

[update]

if in the same class, it work well with some modification. Here the code for DrawingCanvas class:

public class DrawingCanvas extends JPanel {
private boolean isMouseClicked,
        isMouseMoved;
private Point mouseCoordinates;
protected StatusBar statusBar;
protected MenuBar menuBar;


public DrawingCanvas(StatusBar st) {
    setPreferredSize(new Dimension(790, 500));
    setBackground(Color.WHITE);
    statusBar = st;
    Handlers handlers = new Handlers();
    addMouseListener(handlers);
    addMouseMotionListener(handlers);
}

**// inner class**
protected class Handlers extends MouseAdapter implements MouseListener, MouseMotionListener {

    @Override
    public void mouseClicked(MouseEvent e) {
        statusBar.getStatusBar().setText("Mouse clicked.");
    }

    @Override
    public void mouseMoved(MouseEvent e) {            
        statusBar.getStatusBar().setText(String.format("%d, %d", e.getX(),e.getY()));

    }

}
}

and here for MouseEventGUI class:

public class MouseEventGUI extends JFrame {
private DrawingCanvas drawingCanvas;
private StatusBar statusBar;
private MenuBar menuBar;

public MouseEventGUI() {
    super("Learn Mouse Event");

    statusBar = new StatusBar();
    menuBar = new MenuBar();
    drawingCanvas = new DrawingCanvas(statusBar);

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setPreferredSize(new Dimension(750, 560));
    this.add(menuBar, BorderLayout.NORTH);
    this.add(drawingCanvas, BorderLayout.CENTER);       
    this.add(statusBar, BorderLayout.SOUTH);
}
}

But, I plan to make it in separate class for reusable reason.

  • 1
    Please define for us what you mean by "it not working"? You've dumped a lot of code and provided very little description. Please help us be more knowledgeable about your code and your problem so we can have a better chance of being able to help you. As an aside: why AWT and not Swing? Also, your MouseListener doesn't appear to be doing anything measurable. – Hovercraft Full Of Eels Jan 11 '14 at 16:14
  • @Hovercraft: I've up date my posting – Jasmine Law Jan 11 '14 at 16:20
  • 1
    For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve). Does it work if it is in the ***same*** class? That is something you should check first. The `KeyListener` class is notorious for failing. Also, for Swing, typically use key bindings over the AWT based, lower level, `KeyListener`. See [How to Use Key Bindings](http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html) for details on how to use them. – Andrew Thompson Jan 11 '14 at 16:38
  • Shouldn't the listener be added to the drawing canvas and not to `this`? You probably want to listen to mouse events happening on the canvas, not on the frame. – JB Nizet Jan 11 '14 at 16:50
  • @ Andrew, I've make it in the same class. But i plan to make Handler class reusable, it must be in separate class? – Jasmine Law Jan 11 '14 at 18:06
  • OK, but a separate class can still be included in an MCVE. To do that (temporarily) demote the access from `public` (to anything less) and simply paste it in the end of the source code of the class with `main(String[])`. – Andrew Thompson Jan 14 '14 at 19:17

1 Answers1

2

Recommendations:

  • Yes, make Handler a completely separate independent class.
  • Yes, get your listened-to component via the MouseEvent's getSource() method. You can check if it's the right type of object before casting by using the instanceof operator but if you always and only add it to one type of object, then this isn't an issue.
  • Yes, as Camickr and others suggests, don't use AWT's Canvas but rather Swing's JPanel. There are traps that can happen if you mix AWT and Swing components together, you lose a lot of functionality if you use AWT instead of Swing, and there's no need to use Canvas.
  • I would have the MouseListener (in my code, I used a MouseAdapter since it can allow slightly more compact code with less unnecessary code such as empty methods) change the state of the listened to component by calling a setter method.
  • I've had this work well by having that setter method change the state of a "bound" property, one that notifies any PropertyChangeListeners that are interested in its change.
  • And I'd do just that -- add a PropertyChangeListener to the JPanel with the MouseListener and in it change the state of the status JPanel if mouse events occur.

For example:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

@SuppressWarnings("serial")
public class HandlerTester extends JPanel {
   public HandlerTester() {
      Handler handler = new Handler();
      final MyPanel myPanel = new MyPanel();
      myPanel.addMouseListener(handler);
      myPanel.addMouseMotionListener(handler);

      final StatusPanel statusPanel = new StatusPanel();

      myPanel.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {
            if (MyPanel.MOUSE_PRESSED.equals(pcEvt.getPropertyName())) {
               statusPanel.setMousePressed(((Boolean)pcEvt.getNewValue()).booleanValue());
            }
         }
      });

      setLayout(new BorderLayout());
      add(myPanel, BorderLayout.CENTER);
      add(statusPanel, BorderLayout.PAGE_END);
   }

   private static void createAndShowGUI() {
      HandlerTester handlerTester = new HandlerTester();

      JFrame frame = new JFrame("HandlerTester");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(handlerTester);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGUI();
         }
      });
   }
}

class Handler extends MouseAdapter {
   @Override
   public void mousePressed(MouseEvent mEvt) {
      Object src = mEvt.getSource();
      if (src instanceof MyPanel) {
         MyPanel myPanel = (MyPanel) src;
         myPanel.setMousePressed(true);         
      }
   }

   @Override
   public void mouseReleased(MouseEvent mEvt) {
      Object src = mEvt.getSource();
      if (src instanceof MyPanel) {
         MyPanel myPanel = (MyPanel) src;
         myPanel.setMousePressed(false);         
      }
   }
}

@SuppressWarnings("serial")
class MyPanel extends JPanel {
   public static final String MOUSE_PRESSED = "mouse pressed";
   private static final int PREF_W = 600;
   private static final int PREF_H = 400;
   private boolean mousePressed = false;

   public boolean isMousePressed() {
      return mousePressed;
   }

   public void setMousePressed(boolean mousePressed) {
      boolean oldValue = this.mousePressed;
      boolean newValue = mousePressed;
      this.mousePressed = mousePressed;
      firePropertyChange(MOUSE_PRESSED, oldValue, newValue);
   }

   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }
}

@SuppressWarnings("serial")
class StatusPanel extends JPanel {
   private static final String MOUSE_PRESSED = "Mouse Pressed";
   private static final String MOUSE_NOT_PRESSED = "Mouse Not Pressed";
   private JLabel label = new JLabel(MOUSE_NOT_PRESSED);

   public StatusPanel() {
      setLayout(new FlowLayout(FlowLayout.LEADING));
      add(label);
      setBorder(BorderFactory.createEtchedBorder());
   }

   public void setMousePressed(boolean mousePressed) {
      String text = mousePressed ? MOUSE_PRESSED : MOUSE_NOT_PRESSED;
      label.setText(text);
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • I'm trying to learn your code. Can you give me some clue how to get myPanel coordinat in your code? I want to show the mouse cursor when it move in myPanel. – Jasmine Law Jan 11 '14 at 22:09
  • Use my ideas, but write your code. Coordinates are available from the MouseEvent parameter, `getX()`, `getY()`, and `getPoint()` work. – Hovercraft Full Of Eels Jan 11 '14 at 23:30