javaswingjpanelmouselisteneropenslide

Java Swing: Can the mouse make changes to two overlayed JPanels at the same time?


I'm new to swing, and i have the following problem:

I am using the openslide-java library to view whole slide images. There is a class called OpenSlideView that extends JPanel, and its purpose is to view the images. This class has the capability of zooming-in, out and navigating through an image using the mouse, as it utilizes its own mouse listener. I am overlaying two OpenSlideView objects in a JFrame, where one is visible and the other is not, and i want to be able to perform mouse actions on both of them at the same time, even if one of them is not visible. Plainly put, i want the not-visible JPanel to track down the mouse.

Is something like that possible? Even for the JPanel class and not an extension of it?

Thanks in advance.

P.S: I am attaching the code of the method that handles the mouse events for OpenSlideView objects, in case it helps.

   private void registerEventHandlers() {
    // mouse wheel
    addMouseWheelListener(new MouseWheelListener() {
        public void mouseWheelMoved(MouseWheelEvent e) {
            double ds1 = zoomHelper(OpenSlideView.this, e.getX(), e.getY(),
                    e.getWheelRotation());
            double ds2 = zoomHelper(otherView, e.getX(), e.getY(), e
                    .getWheelRotation());
            zoomHelper2(OpenSlideView.this, ds1, e.getX(), e.getY());
            zoomHelper2(otherView, ds2, e.getX(), e.getY());
            zoomHelper3(OpenSlideView.this, ds1);
            zoomHelper3(otherView, ds2);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    // mouse drag
    MouseAdapter ma = new MouseAdapter() {
        private SelectionMode selectionMode;

        private int oldX;

        private int oldY;

        private int slideStartX;

        private int slideStartY;

        private Path2D.Double freehandPath;

        @Override
        public void mousePressed(MouseEvent e) {
            // System.out.println(e);

            requestFocusInWindow();

            if (!SwingUtilities.isLeftMouseButton(e)) {
                return;
            }

            final int ellipseMask = MouseEvent.CTRL_DOWN_MASK
                    | MouseEvent.SHIFT_DOWN_MASK;
            final int freehandMask = MouseEvent.CTRL_DOWN_MASK;
            final int rectMask = MouseEvent.SHIFT_DOWN_MASK;

            if ((e.getModifiersEx() & ellipseMask) == ellipseMask) {
                selectionMode = SelectionMode.ELLIPSE;
            } else if ((e.getModifiersEx() & freehandMask) == freehandMask) {
                selectionMode = SelectionMode.FREEHAND;
            } else if ((e.getModifiersEx() & rectMask) == rectMask) {
                selectionMode = SelectionMode.RECT;
            } else {
                selectionMode = SelectionMode.NONE;
            }

            oldX = e.getX();
            oldY = e.getY();

            double ds = getDownsample();
            slideStartX = (int) ((oldX + viewPosition.x) * ds);
            slideStartY = (int) ((oldY + viewPosition.y) * ds);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (!SwingUtilities.isLeftMouseButton(e)) {
                return;
            }

            int relX = oldX - e.getX();
            int relY = oldY - e.getY();

            double ds = getDownsample();
            int dx = slideStartX;
            int dy = slideStartY;
            int dw = (int) ((e.getX() + viewPosition.x) * ds) - dx;
            int dh = (int) ((e.getY() + viewPosition.y) * ds) - dy;

            if (dw < 0) {
                dx += dw;
                dw = -dw;
            }
            if (dh < 0) {
                dy += dh;
                dh = -dh;
            }

            switch (selectionMode) {
            case NONE:
                translateHelper(OpenSlideView.this, relX, relY);
                translateHelper(otherView, relX, relY);
                repaintHelper(OpenSlideView.this);
                repaintHelper(otherView);
                break;

            case RECT:
                selectionBeingDrawn = new Rectangle(dx, dy, dw, dh);
                // System.out.println(selection);
                repaint();
                break;

            case FREEHAND:
                if (selectionBeingDrawn == null) {
                    // new selection
                    freehandPath = new Path2D.Double();
                    selectionBeingDrawn = freehandPath;

                    freehandPath.moveTo(slideStartX, slideStartY);
                }

                freehandPath.lineTo((e.getX() + viewPosition.x) * ds, (e
                        .getY() + viewPosition.y)
                        * ds);

                repaint();
                break;

            case ELLIPSE:
                selectionBeingDrawn = new Ellipse2D.Double(dx, dy, dw, dh);

                repaint();
                break;
            }
            oldX = e.getX();
            oldY = e.getY();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (selectionMode == SelectionMode.FREEHAND) {
                freehandPath.closePath();
            }
            selectionMode = SelectionMode.NONE;

            if (selectionBeingDrawn != null) {
                Rectangle bb = selectionBeingDrawn.getBounds();
                if (bb.height != 0 && bb.width != 0) {
                    selections.add(new DefaultAnnotation(selectionBeingDrawn));
                    selectionBeingDrawn = null;
                }
            }
            repaint();
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            selectionsVisibleHelper(OpenSlideView.this, true);
            selectionsVisibleHelper(otherView, true);
        }

        @Override
        public void mouseExited(MouseEvent e) {
            selectionsVisibleHelper(OpenSlideView.this, false);
            selectionsVisibleHelper(otherView, false);
        }
    };
    addMouseListener(ma);
    addMouseMotionListener(ma);

    // keyboard
    InputMap inputMap = new InputMap();
    ActionMap actionMap = new ActionMap();

    inputMap.put(KeyStroke.getKeyStroke("SPACE"), "center");
    actionMap.put("center", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            centerHelper(OpenSlideView.this);
            centerHelper(otherView);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("UP"), "scroll up");
    inputMap.put(KeyStroke.getKeyStroke("W"), "scroll up");
    actionMap.put("scroll up", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            translateHelper(OpenSlideView.this, 0, -KEYBOARD_SCROLL_AMOUNT);
            translateHelper(otherView, 0, -KEYBOARD_SCROLL_AMOUNT);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("DOWN"), "scroll down");
    inputMap.put(KeyStroke.getKeyStroke("S"), "scroll down");
    actionMap.put("scroll down", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            translateHelper(OpenSlideView.this, 0, KEYBOARD_SCROLL_AMOUNT);
            translateHelper(otherView, 0, KEYBOARD_SCROLL_AMOUNT);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("LEFT"), "scroll left");
    inputMap.put(KeyStroke.getKeyStroke("A"), "scroll left");
    actionMap.put("scroll left", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            translateHelper(OpenSlideView.this, -KEYBOARD_SCROLL_AMOUNT, 0);
            translateHelper(otherView, -KEYBOARD_SCROLL_AMOUNT, 0);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "scroll right");
    inputMap.put(KeyStroke.getKeyStroke("D"), "scroll right");
    actionMap.put("scroll right", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            translateHelper(OpenSlideView.this, KEYBOARD_SCROLL_AMOUNT, 0);
            translateHelper(otherView, KEYBOARD_SCROLL_AMOUNT, 0);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("L"), "rotate left");
    actionMap.put("rotate left", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {

        }
    });

    inputMap.put(KeyStroke.getKeyStroke("R"), "rotate right");
    actionMap.put("rotate right", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {

        }
    });

    inputMap.put(KeyStroke.getKeyStroke("PLUS"), "zoom in");
    inputMap.put(KeyStroke.getKeyStroke("EQUALS"), "zoom in");
    actionMap.put("zoom in", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            double d1 = zoomHelper(OpenSlideView.this, -1);
            double d2 = zoomHelper(otherView, -1);
            zoomHelper2(OpenSlideView.this, d1);
            zoomHelper2(otherView, d2);
            zoomHelper3(OpenSlideView.this, d1);
            zoomHelper3(otherView, d2);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("MINUS"), "zoom out");
    actionMap.put("zoom out", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            double d1 = zoomHelper(OpenSlideView.this, 1);
            double d2 = zoomHelper(otherView, 1);
            zoomHelper2(OpenSlideView.this, d1);
            zoomHelper2(otherView, d2);
            zoomHelper3(OpenSlideView.this, d1);
            zoomHelper3(otherView, d2);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("Z"), "zoom to fit");
    actionMap.put("zoom to fit", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            // System.out.println("zoom");
            zoomToFit();
            centerSlidePrivate();
            paintBackingStore();
            repaint();
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("1"), "zoom to 1:1");
    actionMap.put("zoom to 1:1", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            // System.out.println("zoom 1:1");
            double d1 = zoomHelper(OpenSlideView.this, Integer.MIN_VALUE);
            double d2 = zoomHelper(otherView, Integer.MIN_VALUE);
            zoomHelper2(OpenSlideView.this, d1);
            zoomHelper2(otherView, d2);
            zoomHelper3(OpenSlideView.this, d1);
            zoomHelper3(otherView, d2);
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    inputMap.put(KeyStroke.getKeyStroke("BACK_QUOTE"), "toggle pins");
    actionMap.put("toggle pins", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
            selectionsAsPins = !selectionsAsPins;
            if (otherView != null) {
                otherView.selectionsAsPins = !otherView.selectionsAsPins;
            }
            repaintHelper(OpenSlideView.this);
            repaintHelper(otherView);
        }
    });

    // install as parents
    InputMap oldInputMap = getInputMap();
    ActionMap oldActionMap = getActionMap();
    inputMap.setParent(oldInputMap.getParent());
    oldInputMap.setParent(inputMap);
    actionMap.setParent(oldActionMap.getParent());
    oldActionMap.setParent(actionMap);
}

Solution

  • i want to be able to perform mouse actions on both of them at the same time

    Doesn't make any sense. If a component is not visible why would you want to do that. Maybe you need to have your component keep its current state. So when you change the state of the top component you update the state of the hidden component. If the hidden component ever becomes visible it will automatically be painted in its current state.

    Plainly put, i want the not-visible JPanel to track down the mouse.

    An event is only dispatched to a single component.

    However, you could use the Component.dispatchEvent(...) method to dispatch a new event to a separate component.