Gus Chambers Gus Chambers - 17 days ago 8
Java Question

How can I highlight JPanels on mouse hover?

I have 16 Jpanels that I want to be highlighted when I hover my mouse over them. I created the JPanels anonymously and then added them to a parent, and added a MouseListener to each of them. I then added a MouseListener to the parent. The thing is, now it just highlights the parent. How can I fix this?

NOTE: Sometimes the JFrame doesn't show anything - you just have to keep running it until it does (usually takes 2-3 tries). Comment if it still isn't working after >5 tries.

HighlightJPanels (creates the JFrame, the container, and the children, and adds the MouseListeners)

public class HighlightJPanels extends JFrame{
private static final long serialVersionUID = 7163215339973706671L;
private static final Dimension containerSize = new Dimension(640, 477);
private JLayeredPane layeredPane;
static JPanel container;

public HighlightJPanels() {
super("Highlight Test");
setSize(640, 477);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);

layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(containerSize);
getContentPane().add(layeredPane);

createContainer();

layeredPane.add(container, JLayeredPane.DEFAULT_LAYER);

createChildren(4, 4);

container.addMouseMotionListener(new HighlightJPanelsContainerMouseListener());
}

private void createChildren(int columns, int rows){
for (int i = 0; i < columns; i++){
for (int j = 0; j < rows; j++){
JPanel child = new JPanel(new BorderLayout());
child.setBackground(Color.LIGHT_GRAY);
child.addMouseListener(new HighlightJPanelsMouseListeners());
container.add(child);
}
}
}

private JPanel createContainer(){
container = new JPanel();
container.setLayout(createLayout(4, 4, 1, 1));
container.setPreferredSize(containerSize);
container.setBounds(0, 0, containerSize.width, containerSize.height);
return container;
}

private GridLayout createLayout(int rows, int columns, int hGap, int vGap){
GridLayout layout = new GridLayout(rows, columns);
layout.setHgap(hGap);
layout.setVgap(vGap);
return layout;
}

public static void main(String[] args) {
new HighlightJPanels();
}
}


HighlightJPanelsChildMouseListeners (creates the MouseListeners that will be added to the children)

public class HighlightJPanelsChildMouseListeners implements MouseListener{
private Border grayBorder = BorderFactory.createLineBorder(Color.DARK_GRAY);

public HighlightJPanelsChildMouseListeners() {
}

public void mouseEntered(MouseEvent e) {
Component comp = HighlightJPanels.container.findComponentAt(HighlightJPanelsContainerMouseListener.eX, HighlightJPanelsContainerMouseListener.eY);
JPanel parent = (JPanel) comp;
parent.setBorder(grayBorder);
parent.revalidate();
}

public void mouseExited(MouseEvent e) {
Component comp = HighlightJPanels.container.findComponentAt(HighlightJPanelsContainerMouseListener.eX, HighlightJPanelsContainerMouseListener.eY);
JPanel parent = (JPanel) comp;
parent.setBorder(null);
parent.revalidate();
}

public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseClicked(MouseEvent e) {}
}


HighlightJPanelsContainerMouseListener (creates the MouseListener that will be added to the container)

public class HighlightJPanelsContainerMouseListener implements MouseMotionListener{
static int eX;
static int eY;

public void mouseDragged(MouseEvent e) {}

public void mouseMoved(MouseEvent e) {
eX = e.getX();
eY = e.getY();
}
}

Answer

The problem is being caused by how you find the JPanel to highlight, on this line:

Component comp = HighlightJPanels.container.findComponentAt(HighlightJPanelsContainerMouseListener.eX, HighlightJPanelsContainerMouseListener.eY);

Fortunately, there's already a function that will do what you want. You can just use getSource() on the event, and it will tell you which panel to highlight. So change your function to this:

public void mouseEntered(MouseEvent e) {
    JPanel parent = (JPanel)e.getSource();
    parent.setBorder(grayBorder);
    parent.revalidate();
}

and do the same thing with mouseExited, and you'll see it highlight the correct panel. And this will remove the need for HighlightJPanelsContainerMouseListener.