java - 通过 JScrollPane 异常行为重新调度 MouseEvent

标签 java swing mouseevent jscrollpane dispatchevent

我从这里修改了一些代码:https://stackoverflow.com/a/13357269/1360074

由于 JScrollPane 存在未传递 MouseEvent 的已知错误,因此我使用 FakeMouseListener 进行了解决方法。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.LayoutManager;
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() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(600, 400);
                }

            };
            JPanel panel2 = new JPanel() {
                @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();
            pane.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(panel1.getComponentAt(point));
        System.out.println(panel1.getComponent(0));
    }
}

private class FakeMouseListener extends MouseAdapter {
     @Override
     public void mousePressed(MouseEvent me) {
         panel1.dispatchEvent(me);
     }
}
}

现在,如果单击边框左侧左侧的绿色边框内,我会得到:

java.awt.event.MouseEvent[MOUSE_PRESSED,(9,169),absolute(66,248),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1] on javax.swing.JScrollPane[,49
LostMouseEvent$2$1[,0,0,600x400,layout=CircleLayout,alignmentX=0.0,alignmentY=0.0,border=javax.swing.border.LineBorder@633d51
javax.swing.JScrollPane[,49,49,503x303,layout=javax.swing.ScrollPaneLayout$UIResource,alignmentX=0.0,alignmentY=0.0,

如果我点击中间我会得到:

java.awt.event.MouseEvent[MOUSE_PRESSED,(247,147),absolute(304,226),button=1,modifiers=Button1,extModifiers=Button1,clickCount=1] on javax.swing.JScrollPane[,
    javax.swing.JScrollPane[,49,49,503x303,layout=javax.swing.ScrollPaneLayout$UIResource,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.metal.
    javax.swing.JScrollPane[,49,49,503x303,layout=javax.swing.ScrollPaneLayout$UIResource,alignmentX=0.0,alignmentY=0.0,border=javax.swing.plaf.metal.

这是为什么呢?当我重新调度MouseEvent时,是否需要修改它的坐标?

CircleLayout 的代码是

    import java.awt.Component;
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.LayoutManager;


    public class CircleLayout implements LayoutManager {
        private int heightGap;

    public CircleLayout () {
        heightGap = 0;
    }

    public CircleLayout (int heightGap) {
        this.heightGap = heightGap;
    }

    /**
    * Arranges the parent's Component objects in either an Ellipse or a Circle.
    * Ellipse is not yet implemented.
    */
    public void layoutContainer (Container parent) {
        int x, y, w, h, s, c;
        int childCompNum = parent.getComponentCount();

        int parentWidth = (int)parent.getSize().width;
        int parentHeight = (int)parent.getSize().height;

        int centerX = (int) (parentWidth / 2);
        int centerY = (int) (parentHeight / 2);

        double angleOffset = 0.5 * Math.PI;

        Component childComp = null;
        for (int i = 0; i < childCompNum; i++) {
            childComp = parent.getComponent(i);
            w = childComp.getPreferredSize().width;
            h = childComp.getPreferredSize().height;

            if (childCompNum == 1) {
                x = centerX - (int)w / 2;
                y = centerY - (int)h / 2;
            } else {
                c = (int) (centerX * Math.cos((2 * i * Math.PI + angleOffset) / childCompNum));
                s = (int) (centerY * Math.sin((2 * i * Math.PI + angleOffset) / childCompNum));

                x = c + centerX - (int)w / 2;
                y = s + centerY - (int)h / 2;

                if (x + w  > parentWidth) {x = (int)(parentWidth - w); }
                if (y + h + heightGap > parentHeight) {y = (int)(parentHeight - h -heightGap); }
                if (x < 0) {x = 0; }
                if (y < 0) {y = 0; }
            }

            childComp.setBounds(x, y, w, h);
        }
    }

    /** For compatibility with LayoutManager interface */
    public void addLayoutComponent (String name, Component comp) {}

    public Dimension preferredLayoutSize(Container target) {
        return target.getSize();
    }

    public Dimension minimumLayoutSize(Container target) {
        return target.getSize();
    }

    public void removeLayoutComponent(Component comp) {}
}

UPD:我已将 FakeMouseListener 修改为

     public void mousePressed(MouseEvent me) {
         JScrollPane pane = (JScrollPane)me.getSource();
         MouseEvent newMe = SwingUtilities.convertMouseEvent(pane, me, pane.getViewport());
         panel1.dispatchEvent(me);
     }

但有相同的行为。

最佳答案

代码

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Rectangle;
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;
    private JPanel panel2 = new JPanel();

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

            @Override
            public void run() {
                LostMouseEvent lostMouseEvent = 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);
                    }
                };
                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) {
            Rectangle rec = SwingUtilities.convertRectangle(panel2, panel2.getVisibleRect(), panel1);
            System.out.println(me);
            Point point = me.getPoint();
            System.out.println(panel1.getComponentAt(point));
            System.out.println(panel1.getComponent(0));
        }
    }

    private class FakeMouseListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent me) {
            JScrollPane pane = (JScrollPane) me.getSource();
            MouseEvent newMe = SwingUtilities.convertMouseEvent(pane, me, pane.getViewport());
            panel1.dispatchEvent(me);
        }
    }
}

返回

    Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException:  AAA_Format.LostMouseEvent$2$2 cannot be

cast to javax.swing.JScrollPane at AAA_Format.LostMouseEvent$FakeMouseListener.mousePressed(LostMouseEvent.java:95) at java.awt.Component.processMouseEvent(Component.java:6264) at javax.swing.JComponent.processMouseEvent(JComponent.java:3267) at java.awt.Component.processEvent(Component.java:6032) at java.awt.Container.processEvent(Container.java:2041) at java.awt.Component.dispatchEventImpl(Component.java:4630) at java.awt.Container.dispatchEventImpl(Container.java:2099) at java.awt.Component.dispatchEvent(Component.java:4460) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4577) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4235) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168) at java.awt.Container.dispatchEventImpl(Container.java:2085) at java.awt.Window.dispatchEventImpl(Window.java:2478) at java.awt.Component.dispatchEvent(Component.java:4460) at java.awt.EventQueue.dispatchEvent(EventQueue.java:599) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

编辑

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();
                pane.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) {
            JScrollPane pane = (JScrollPane) me.getSource();
            MouseEvent newMe = SwingUtilities.convertMouseEvent(pane.getViewport(), 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);
        }
    }
}

编辑2

更符合逻辑的可以在 FakeMouseListener 中替换,来自

JScrollPane pane = (JScrollPane) me.getSource(); 
MouseEvent newMe = SwingUtilities.convertMouseEvent(pane.getViewport(), me, panel1);

JPanel panel2 = (JPanel) me.getSource(); 
MouseEvent newMe = SwingUtilities.convertMouseEvent(panel2, me, panel1);

关于java - 通过 JScrollPane 异常行为重新调度 MouseEvent,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13374880/

相关文章:

java - 使用 DFS 解决 8-Puzzle

java - 修改 JTable 单元格中的文本对齐方式

java - GridBagLayout 上的 swing 替换组件

java.sql.SQLException : Smart-large-object error informix

java - 将图像从数据库写入jsp

java - Eureka 服务器的问题

Java:图像上的 JComboBox 选择问题

java - 使用 mouseClicked() 时拖动的鼠标坐标也被计算在内?

windows - MFC 鼠标激活 : Where is focus if you eat the mouse event?

javascript - 数组长度在清空后不会增加,并且无法在 HTMLCollection 上添加鼠标事件