2

I have modified a little code from here: https://stackoverflow.com/a/13357269/1360074

Since there is known bug with JScrollPane not passing MouseEvent up I did a workaround with 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);
     }
}
}

Now if click inside green border on the left side just next to border I get:

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,

If I click in the middle I get:

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.

Why is that? Do you I need to modify coordinates of MouseEvent when I re-dispatch it?

Code for CircleLayout is

    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: I have modified FakeMouseListener to

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

But have same behavior.

Community
  • 1
  • 1
Nikolay Kuznetsov
  • 9,467
  • 12
  • 55
  • 101
  • 2
    (again) have to use SwingUtilities.convertXxxXxx in connection with child v.s.parent, question CircleLayout is from this forum, made by aterai – mKorbel Nov 14 '12 at 08:10
  • pi - pi - pi... piiiip, quite understand, but to avoiding to use that for Compound JComponens(have to derive to the childs brrrr), there are two issues, have to determine if mouse click contains child JPanel, if is bounds valid or not, if yes then to dispatchEvent from parent JPanel to child, otherwise event stays valid for parent, notice there could be Point valid for Borders too don't forger about :-) – mKorbel Nov 14 '12 at 08:25
  • you'll "never" convertPoint from child to JScrollPane, because required whatever un_know woodoo for me, simple to convertPoint from child to the JViewport, JViewport is about visible Rectangle from JScrollPane – mKorbel Nov 14 '12 at 08:39
  • [all required logics is here](http://www.javalobby.org/java/forums/t21355.html), see events from one window to another is about desired dispatchEvent(), try resize, move but I miss there if contains in JViewport, have to add (nobody knows, minus one of possible exceptions) – mKorbel Nov 14 '12 at 09:07
  • @mKorbel I don't quite understand all of these. But I want to use panel1.getComponentAt(point) to get JScrollPane all the time. Is modifying coordinates of MouseEvent would be sufficient? – Nikolay Kuznetsov Nov 14 '12 at 10:24
  • `not`, be sure (based on that you added listener to `JScrollPane`) then have to know `Point` in `JViewport` only and then to redirect (`dispatchEvent`) to the `getDeepestComponentAt` .... – mKorbel Nov 14 '12 at 10:51
  • not code posted by your honesty added second MouseListener to JScrollPane, isn't it???, or your whole issue is based on this typo :-), I'll ki** you, right ... – mKorbel Nov 14 '12 at 11:00
  • Sorry, code is okay, I got confused in previous comment. – Nikolay Kuznetsov Nov 14 '12 at 11:02
  • @mKorbel, please see my update. And I don't get where and why I use getDeepestComponentAt if I know that panel1 should get the event? – Nikolay Kuznetsov Nov 14 '12 at 11:55
  • [will help you?](http://stackoverflow.com/a/9261096/714968), I think that I posted code examples for all convertXxxXxx too, – mKorbel Nov 14 '12 at 11:58
  • @mKorbel It might help if I understand why to use it. Can you give a hint if the UPD code is correct or not? – Nikolay Kuznetsov Nov 14 '12 at 12:12
  • JScrollPane doesn't returns mouse event or returns exception – mKorbel Nov 14 '12 at 12:29
  • @mKorbel, What do you mean? This statement relates to which line of code? – Nikolay Kuznetsov Nov 14 '12 at 12:31

1 Answers1

3

code

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);
        }
    }
}

returns

    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)

EDIT

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);
        }
    }
}

EDIT 2

more logical could be replace inside FakeMouseListener, from

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

to

JPanel panel2 = (JPanel) me.getSource(); 
MouseEvent newMe = SwingUtilities.convertMouseEvent(panel2, me, panel1);
mKorbel
  • 109,525
  • 20
  • 134
  • 319