KeyPressed and mousePressed Event in an unfocused Component

后端 未结 2 1669
南方客
南方客 2020-12-03 18:23
  1. What are several ways of detecting a key stroke without the need of focusing on the component that the event was implemented? Here\'s my idea on this:
    Even wit

相关标签:
2条回答
  • 2020-12-03 19:14
    • all JComponent has method dispatchEvent,

    • you can to redirect mouse & key event from one JComponent to the another

    • for JButton to use doClick() instead

    for example

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Point;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import javax.swing.BorderFactory;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.SwingUtilities;
    
    public class LostMouseEvent {
    
        private JPanel panel1;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    new LostMouseEvent();
                }
            });
        }
    
        public LostMouseEvent() {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    panel1 = new JPanel() {
                        private static final long serialVersionUID = 1L;
    
                        @Override
                        public Dimension getPreferredSize() {
                            return new Dimension(600, 400);
                        }
                    };
                    JPanel panel2 = new JPanel() {
                        private static final long serialVersionUID = 1L;
    
                        @Override
                        public Dimension getPreferredSize() {
                            return new Dimension(500, 300);
                        }
                    };
                    JScrollPane pane = new JScrollPane(panel2);
                    panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
                    panel2.setBorder(BorderFactory.createLineBorder(Color.green));
                    panel1.setLayout(new CircleLayout());
                    panel1.add(pane);
                    frame.add(panel1);
                    MouseListener rml = new RealMouseListener();
                    panel1.addMouseListener(rml);
                    MouseListener fml = new FakeMouseListener();
                    panel2.addMouseListener(fml);
                    frame.pack();
                    frame.setVisible(true);
    
                }
            });
        }
    
        private class RealMouseListener extends MouseAdapter {
    
            @Override
            public void mousePressed(MouseEvent me) {
                System.out.println(me);
                Point point = me.getPoint();
                System.out.println(me.getX());
                System.out.println(me.getXOnScreen());
                System.out.println(me.getY());
                System.out.println(me.getYOnScreen());
            }
        }
    
        private class FakeMouseListener extends MouseAdapter {
    
            @Override
            public void mousePressed(MouseEvent me) {
                JPanel panel2 = (JPanel) me.getSource();
                MouseEvent newMe = SwingUtilities.convertMouseEvent(panel2, me, panel1);
                System.out.println(newMe.getX());
                System.out.println(newMe.getXOnScreen());
                System.out.println(newMe.getY());
                System.out.println(newMe.getYOnScreen());
                panel1.dispatchEvent(me);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-03 19:27

    For the first question, regarding the KeyStroke thingy, I guess you can use KeyBinding instead of using KeyListener, that can give you the desired result, without the focus related issues of the component in question, though within the Java Dimensions.

    In the example below, the focus is on the JTextField first, so if you will Press CTRL + D, then the paintAction thingy attached to the CustomPanel will work, even though the focus lies with the JTextField.

    Though if you will use the setMnemonic() method for JButton, then the JButton will gain focus and will perform it's own action associated with it, which is to draw Ovals. This you can see by Pressing ALT + C, to see the desired effect. Again to perform the drawing related thingy, both the components in question don't need the focus, but still they respond to the KeyStrokes.

    Here is the example code :

    import java.awt.*;
    import java.awt.event.*;
    import java.util.Random;
    import javax.swing.*;
    
    public class SSCCE
    {
        private final int WIDTH = 500;
        private final int HEIGHT = 500;
        private CustomPanel customPanel;
        private JButton circleButton;
        private JTextField tfield;
        private Random random;
        private int mode;
    
        private Action paintAction = new AbstractAction()
        {
            @Override
            public void actionPerformed(ActionEvent ae)
            {
                mode = random.nextInt(3);
                Color color = new Color(random.nextFloat(), random.nextFloat()
                                                            , random.nextFloat(), random.nextFloat());
                customPanel.setValues(random.nextInt(WIDTH), 
                                random.nextInt(HEIGHT), random.nextInt(WIDTH), 
                                                                        random.nextInt(HEIGHT), color, mode);
            }
        };
    
        private ActionListener buttonAction = new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent ae)
            {
                Color color = new Color(random.nextFloat(), random.nextFloat()
                                                            , random.nextFloat(), random.nextFloat());
                customPanel.setValues(random.nextInt(WIDTH), 
                                random.nextInt(HEIGHT), random.nextInt(WIDTH), 
                                                                        random.nextInt(HEIGHT), color, 2);
            }
        };
    
        public SSCCE()
        {
            random = new Random();
        }
    
        private void displayGUI()
        {
            JFrame frame = new JFrame("SSCCE");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    
            JPanel contentPane = new JPanel();
            contentPane.setLayout(new BorderLayout(5, 5));
    
            customPanel = new CustomPanel();
            customPanel.getInputMap(
                JComponent.WHEN_IN_FOCUSED_WINDOW).put(
                    KeyStroke.getKeyStroke(KeyEvent.VK_D
                        , InputEvent.CTRL_DOWN_MASK), "paintAction");
            customPanel.getActionMap().put("paintAction", paintAction);
    
            JPanel footerPanel = new JPanel();
            circleButton = new JButton("Draw Circle");
            circleButton.setMnemonic(KeyEvent.VK_C);
            circleButton.addActionListener(buttonAction);
    
            tfield = new JTextField(20);
            tfield.setText("USELESS, just to get the focus for itself.");
            tfield.requestFocusInWindow();
            footerPanel.add(tfield);
            footerPanel.add(circleButton);
    
            contentPane.add(customPanel, BorderLayout.CENTER);
            contentPane.add(footerPanel, BorderLayout.PAGE_END);
    
            frame.setContentPane(contentPane);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        public static void main(String... args)
        {
            EventQueue.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    new SSCCE().displayGUI();
                }
            });
        }
    }
    
    class CustomPanel extends JPanel
    {
        private final int WIDTH = 500;
        private final int HEIGHT = 500;
        private int mode = 0;
        private Color colorShape;
        private int x = 0;
        private int y = 0;
        private int width = 0;
        private int height = 0;
    
        public void setValues(int x, int y, int w, int h, Color color, int mode)
        {
            this.x = x;
            this.y = y;
            this.width = w;
            this.height = h;
            this.colorShape = color;
            this.mode = mode;
    
            repaint();
        }
    
        @Override
        public Dimension getPreferredSize()
        {
            return (new Dimension(WIDTH, HEIGHT));
        }
    
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            g.setColor(colorShape);
            if (mode == 1)
                g.fillRect(x, y, width, height);
            else if (mode == 2)
                g.fillOval(x, y, width, height);
        }
    }
    

    Related to mousePressed() thingy, @mKorbel, had presented the whole thingy as usual in a delightful manner.

    And regarding your second question, seems like you yourself had done some homework on that. Seems like either using what you showed in your question is the workaround for catching Operating System related events and transfer that to your Java Application or Java Native Interface, I guess might also can work for this.

    0 讨论(0)
提交回复
热议问题