3

Is there a easier way for a JComponent to request focus when you click on it than having to set up a MouseListener?

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
Jeremy
  • 98
  • 7
  • 1
    Why not use the MouseListener? How else can you conceive your application being notified of the mouse press? What overall problem are you trying to solve? Can you show pertinent code? – Hovercraft Full Of Eels Nov 11 '17 at 18:07
  • I have quite a few very simple JComponents that would be made more complicated than they need be by MouseListeners, I was hoping there was a function within the JComponents library that could automatically request focus on a click event, or perhaps a default focus, if it's not needed anywhere else. – Jeremy Nov 11 '17 at 18:10
  • Okay. That was that was pretty much essence of my question. Thank you for your help. Mouse Listeners it is. – Jeremy Nov 11 '17 at 18:13
  • No, it has to be a MouseListener. – Hovercraft Full Of Eels Nov 11 '17 at 18:18
  • A FocusListener would work with tabbing, but still the mouse click cannot be captured without the MouseListener. – Hovercraft Full Of Eels Nov 11 '17 at 18:19
  • It may be `ActionListener`. – Yoda Nov 11 '17 at 18:26
  • @Yoda: no, not necessary. Components that accept ActionListener already gain focus on mouse press. There's no need (or desire) to add a MouseListener to a JButton. I'm assuming that the OP is talking about other components that don't normally gain focus such as JLabels and JPanels. – Hovercraft Full Of Eels Nov 11 '17 at 18:27
  • @SynchroDynamic: What do you mean? – Jeremy Nov 19 '17 at 21:57

2 Answers2

4

You need to add a MouseListener to the component to be able for it to respond to mouse press and request application focus. The easiest way to do this for multiple components is with a loop, such as a for loop used at component creation, or else place the components within a container such as an ArrayList, and loop through this collection, adding the MouseListener (MouseAdapter). For example:

private class MyMouse extends MouseAdapter {
    @Override
    public void mousePressed(MouseEvent e) {
        JComponent comp = (JComponent) e.getSource();
        comp.requestFocusInWindow();
    }
}

Which can be used like so:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.border.Border;

@SuppressWarnings("serial")
public class FocusTest extends JPanel {

    private static final int ROWS = 6;
    private static final int COLS = 10;
    protected static final int THICKNESS = 5;
    private static final int PREF_W = 500;
    private static final int PREF_H = 300;
    private static final Color SELECTED_COLOR = Color.RED;
    private static final Color UNSELECTED_COLOR = Color.LIGHT_GRAY;

    public FocusTest() {
        setLayout(new GridLayout(ROWS, COLS, 2, 2));
        MyMouse myMouse = new MyMouse();
        MyFocus myFocus = new MyFocus();
        for (int i = 0; i < ROWS; i++) {
            for (int j = 0; j < COLS; j++) {
                String text = String.format("[%d, %d]", j, i);
                final JLabel label = new JLabel(text, SwingConstants.CENTER);
                label.setBorder(createBorder(false));
                label.addFocusListener(myFocus);
                label.addMouseListener(myMouse);
                label.setFocusable(true);
                add(label);
            }
        }
    }

    public Border createBorder(boolean selected) {
        Color color = selected ? SELECTED_COLOR : UNSELECTED_COLOR;
        return BorderFactory.createLineBorder(color, THICKNESS);
    }

    private class MyMouse extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            JComponent comp = (JComponent) e.getSource();
            comp.requestFocusInWindow();
        }
    }

    private class MyFocus extends FocusAdapter {

        @Override
        public void focusGained(FocusEvent e) {
            JComponent comp = (JComponent) e.getSource();
            comp.setBorder(createBorder(true));
        }

        @Override
        public void focusLost(FocusEvent e) {
            JComponent comp = (JComponent) e.getSource();
            comp.setBorder(createBorder(false));
        }
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension superSize = super.getPreferredSize();
        if (isPreferredSizeSet()) {
            return superSize;
        }
        int w = Math.max(PREF_W, superSize.width);
        int h = Math.max(PREF_H, superSize.height);
        return new Dimension(w, h);
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("FocusTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new FocusTest());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
0

You could inherit from a class, like JLabel a class called JFocusedLabel, which would have a MouseListener, which would do the focusing. You may need to implement 5-6 such classes, but at the end of the day you would not have to add such a listener to each and every JComponent object you have. Just instantiate those classes instead of their standard parents.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175