Search code examples
javaswingmouselisteneruimanager

Java Mouse Listener error with UIManager SetLookAndFeel


The below code displays a JFrame with a JMenu and a [custom] JPanel.

I set the look-and-feel (LAF) to Windows LAF by calling method UIManager.setLookAndFeel

I click on the JMenu with the mouse and then I move the mouse onto the [custom] JPanel – while the menu is still visible. Then I click the mouse again and the mousePressed method of the MouseListener on my [custom] JPanel does not get called, even though the mouseReleased method does.

If I do not explicitly set the LAF, i.e. if I use the default LAF, it works fine.

How can I fix this?

Below are two classes: MListen and Panel. Class MListen declares a main method, so you can launch that class. Then you can perform the actions described above to reproduce the behavior. Class Panel is my custom JPanel.

I want the mousePressed method of the MouseListener, in class Panel to be called every time that the mouse is pressed if it is on the Panel.

  • MListen.java
package drawer.Main;
import javax.swing.*;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.*;

public class MListen extends JFrame{

    public MListen(){
        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        setSize(800, 600);
        //setExtendedState(MAXIMIZED_BOTH);
        setLayout(new BorderLayout());
        getContentPane().setBackground(Color.WHITE);
        
        
        Panel panel = new Panel();
        JMenuBar bar = new JMenuBar();
        JMenu file = new JMenu("file");
        JMenuItem open = new JMenuItem("open");
        JButton b = new JButton("AB");
        file.add(b);
        
        bar.add(file);
        file.add(open);
        setJMenuBar(bar);
        
        add(panel, BorderLayout.CENTER);
        
        setVisible(true);
        
    }
    
    public static void main(String[] args){
        javax.swing.SwingUtilities.invokeLater(new Runnable() {  
              
            public void run() {
                try {
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                        | UnsupportedLookAndFeelException e) {
                    e.printStackTrace();
                }
                new MListen();  
            }  
        });  
    }

}
  • Panel.java
package drawer.Main;

import java.awt.*;
import java.awt.event.*;
import javax.swing.JPanel;

public class Panel extends JPanel implements MouseListener, MouseMotionListener{
    public float size;
    public Color color;
    public boolean DoDraw;

    public Panel(){
        addMouseListener(this);
        setFocusable(true);
        addMouseMotionListener(this);
        setBackground(Color.RED);
    }

    @Override
    public void mouseDragged(MouseEvent arg0) {
        //System.out.println("Drag");
        
    }

    @Override
    public void mouseMoved(MouseEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseClicked(MouseEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseEntered(MouseEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mousePressed(MouseEvent arg0) {
        System.out.println("Press");
        // TODO Auto-generated method stub
        
    }

    @Override
    public void mouseReleased(MouseEvent arg0) {
        System.out.println("relese");
        // TODO Auto-generated method stub
        
    }
}

Try running the above code clicking on the red JPanel. The console will display "Press". Now click on the JMenu and then on the JPanel and "Press" will not be displayed in the console.

Thanks!

  • Edit I need the UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); Can I fix this without removing it? Also I need the MousePressed on the first time

Solution

  • Here is a bad answer, but it should work. You can capture all of the events before they're delegated.

    This can be added to your JPanel constructor.

    long eventMask = AWTEvent.MOUSE_EVENT_MASK;
    Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener() {
        public void eventDispatched(AWTEvent e){
                    MouseEvent evt = (MouseEvent)e;
                    if( evt.getSource() == this && evt.getId()==MouseEvent.MOUSE_PRESSED ){
                        this.mousePressed(evt);
                        evt.consume();
                    }
        }
    }, eventMask );
    

    This captures all mouse events check that they original from the correct panel, checks if it is a mousePressed event and calls the method.

    This is good code for debugging, but not good to find in your project.