views:

105

answers:

2

I have a JPanel that I have created a MouseListener for and I am seeing some behavior that I can't explain.

Usually when I click the mouse within the JPanel, I see the following events fire:

mousePressed
mouseReleased
mouseClicked

On some occasions, I don't see the mouseClicked event fire, I only see:

mousePressed
mouseReleased

I don't think I'm doing anything out of the ordinary when I click these times. Could anyone explain why I might not be seeing the mouseClicked event?

I'm not sure if it's relevant, but I do have an animation running in the panel using a javax.swing.Timer.

Any help is appreciated.

EDIT: adding test code that replicates problem. I'm not sure, but I wonder if my mouse has anything to do with it. I have one of those super sensitive gaming mice (from my old COD4 days).

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Test {

    public static void main(String[] args) {
        final Test test = new Test();
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                test.createAndShowGUI();
            }
        });
    }

    protected void createAndShowGUI() {
        JFrame frame = new JFrame();
        frame.setPreferredSize(new Dimension(1024, 768));
        frame.setTitle("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setBackground(Color.WHITE);

        panel.addMouseListener(new MouseListener() {
            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println(":MOUSE_RELEASED_EVENT:");
            }
            @Override
            public void mousePressed(MouseEvent e) {
                System.out.println("----------------------------------\n:MOUSE_PRESSED_EVENT:");
            }
            @Override
            public void mouseExited(MouseEvent e) {
                System.out.println(":MOUSE_EXITED_EVENT:");
            }
            @Override
            public void mouseEntered(MouseEvent e) {
                System.out.println(":MOUSE_ENTER_EVENT:");
            }
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println(":MOUSE_CLICK_EVENT:");
            }
        });

        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }

}
+1  A: 

I think you're seeing an artifact of how System.out uses the console. The example below shows a more consistent picture, with matching MOUSE_RELEASED and MOUSE_CLICKED times.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
import javax.swing.text.DefaultCaret;

public class Test {

    private EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
    private JLabel p = new JLabel(" ", JLabel.CENTER);
    private JLabel r = new JLabel(" ", JLabel.CENTER);
    private JLabel c = new JLabel(" ", JLabel.CENTER);
    private JTextArea ta = new JTextArea();
    private MouseEvent lastPressed;
    private MouseEvent lastReleased;
    private MouseEvent lastClicked;

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

            @Override
            public void run() {
                new Test().createAndShowGUI();
            }
        });
    }

    protected void createAndShowGUI() {
        final JFrame frame = new JFrame();
        frame.setLayout(new GridLayout(0, 1));
        frame.setTitle("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final JPanel upper = new JPanel(new GridLayout(0, 1));
        upper.add(p);
        upper.add(r);
        upper.add(c);

        final JPanel middle = new JPanel(new GridLayout());
        ta.setEditable(false);
        DefaultCaret caret = (DefaultCaret)ta.getCaret();
        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
        JScrollPane sp = new JScrollPane(ta);
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        sp.setPreferredSize(new Dimension(450, 100));
        middle.add(sp);

        final JPanel lower = new JPanel();
        lower.setBackground(Color.yellow);
        lower.add(new JLabel("Click me!", JLabel.CENTER));
        lower.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                Test.this.lastPressed = e;
                p.setText("MOUSE_PRESSED: " + e.getWhen());
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                Test.this.lastReleased = e;
                r.setText("MOUSE_RELEASED: " + e.getWhen());
                if (lastClicked == null) {
                    long dt = lastReleased.getWhen();
                    dt = dt - lastPressed.getWhen();
                    ta.append(lastReleased.getWhen()
                        + " - " + lastPressed.getWhen()
                        + " = " + dt + "\n");
                }
                lastClicked = null;
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                Test.this.lastClicked = e;
                long dt = e.getWhen() - lastReleased.getWhen();
                c.setText("MOUSE_CLICK: " + e.getWhen() + " delta: " + dt);
            }
        });
        lastClicked = new MouseEvent(lower, 0, 0, 0, 0, 0, 0, false);

        frame.add(upper);
        frame.add(middle);
        frame.add(lower);
        frame.pack();
        frame.setVisible(true);
        final Timer t = new Timer(100, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                eventQueue.postEvent(new MouseEvent(lower,
                    MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(),
                    MouseEvent.BUTTON1, 0, 0, 1, false));
            }
        });
        t.start();
    }
}
trashgod
Thanks for the suggestion, but I'm able to reproduce the behavior with your example. This is killing me, I'm thinking of writing my own logic to determine clicks... here I go down the rabbit hole.... Since this seems like such a unique problem, I'm starting to think this is somehow hardware/driver related.
BillMan
@BillMan: I've updated the example to show the behavior. I suspect the platform is rejecting apparent noise/bounce.
trashgod
A: 

Hey all,

I think I found the problem here. I was getting intermediate mouseDragged events between the mousePress and mouseRelease. mouseMoved didn't seem to cause the problem, but mouseDragged did.

I'm not sure of the right solution now, but at least now I can explain what is happening.

Cheers

-Bill

BillMan