映射鼠标事件坐标

时间:2017-03-28 15:13:44

标签: java swing mouseevent jlayer

我已经实现了一个JLayer<JPanel>组件,它自己绘制了一个缩放的Graphics组件,因此所有下行组件也都会被缩放。 此JLayer作为ContentPane应用于JFrame组件。

主要问题是所有变焦实际上仅适用于图形,并且组件的实际尺寸和位置保持不变。这意味着所有鼠标事件分别发生在用户看到的错误位置。

我是调整它的王者,它在框架的顶部定义了一个GlassPane JComponent,它有自己的MouseInputAdapter,它将MouseEvent重新发送到底层组件使用SwingUtilities.getDeepestComponentAt()。这是通过创建一个新的MouseEvent来完成的,其中鼠标坐标根据缩放值进行映射。 (获得修改How to use RootPanes教程)

此方法显然不令人满意,因为很多事件根本无法触发(例如,所有降序组件触发的MOUSE_ENTERED事件)。 另一方面,使用LayerUI.paint()覆盖意味着我必须有一些重新映射所有鼠标坐标的东西。

  1. 有没有办法在不破坏内部MouseEvent处理的情况下映射鼠标坐标?

  2. 还有另一种方法可以放大组件的位图,同时还可以修改实际位置和大小吗?我有点尝试过,但是调用内部组件的setSize()似乎有时会再次调用LayerUi.paint(),所以我得到的是一些与实际窗口小部件位置断开的更大的图形

1 个答案:

答案 0 :(得分:0)

这是我迄今为止所做的,感谢MadProgrammer和PBar扩展,在Java 8中使用JLayer。

TransformUI本身包含了P​​Bar org.pbjar.jxlayer.plaf.ext.MouseEventUIorg.pbjar.jxlayer.plaf.ext.TransformUI

package jzoom.transform;

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JComponent;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.LayerUI;

/**
 * 
 * This UI apply an {@link AffineTransform} to all the visible objects, and apply the inversion
 *  of the same transform to all the mouse event's coordinates
 * 
 * @author Andrea.Maracci based on the pbjar JXLayer extension
 *
 */
public class TransformUI extends LayerUI<JComponent> {
    private static final long serialVersionUID = 1L;

    private Component lastEnteredTarget, lastPressedTarget;

    private final Set<JComponent> originalDoubleBuffered = new HashSet<JComponent>();
    private AffineTransform transform = new AffineTransform();
    private JLayer<JComponent> installedLayer;
    private boolean dispatchingMode = false;

    /**
     * Process the mouse events and map the mouse coordinates inverting the internal affine transformation.
     * 
     * @param
     * event the event to be dispatched
     * layer the layer this LayerUI is set to
     * 
     */
    @Override
    public void eventDispatched(AWTEvent event, final JLayer<? extends JComponent> layer) {
        if (event instanceof MouseEvent) {
            MouseEvent mouseEvent = (MouseEvent) event;
            /*
             * The if discriminate between generated and original event.
             * Removing it cause a stack overflow caused by the event being redispatched to this class.
             */
            if (!dispatchingMode) {
                // Process an original mouse event
                dispatchingMode = true;
                try {
                    redispatchMouseEvent(mouseEvent, layer);
                } finally {
                    dispatchingMode = false;
                }
            } else {
                /*
                 * Process generated mouse events
                 * Added a check, because on mouse entered or exited, the cursor
                 * may be set to specific dragging cursors.
                 */
                if (MouseEvent.MOUSE_ENTERED == mouseEvent.getID() || MouseEvent.MOUSE_EXITED == mouseEvent.getID()) {
                    layer.getGlassPane().setCursor(null);
                } else {
                    Component component = mouseEvent.getComponent();
                    layer.getGlassPane().setCursor(component.getCursor());
                }
            }
        } else {
            super.eventDispatched(event, layer);
        }
        layer.repaint();
    }

    /**
     * Set the affine transformation applied to the graphics
     * @param transform the transformation
     */
    public void setTransform(AffineTransform transform) {
        if (transform != null) {
            this.transform = transform;
        }
    }

    /**
     * Return the affine transformation applied to the graphics
     * @return the transformation
     */
    public AffineTransform getTransform() {
        return transform;
    }

    /**
     * Paint the specified component {@code c} applying the transformation on it's graphic
     * 
     * @param
     * g - the Graphics context in which to paint
     * c - the component being painted
     */
    @Override
    public void paint(Graphics g, JComponent c) {
        if (g instanceof Graphics2D) {
            Graphics2D g2 = (Graphics2D) g.create();
            JLayer<? extends JComponent> l = (JLayer<? extends JComponent>) c;
            g2.transform(transform);
            paintLayer(g2, l);
            g2.dispose();
        }
    }

    /**
     * Paint the view decorated by the JLayer {@code layer} and the JLayer itself
     * 
     * @param g2
     * @param layer the layer this LayerUI is set to
     */
    private final void paintLayer(Graphics2D g2, JLayer<? extends JComponent> layer) {
        JComponent view = layer.getView();
        if (view != null) {
            if (view.getX() < 0 || view.getY() < 0) {
                setToNoDoubleBuffering(view);
                g2.translate(view.getX(), view.getY());
                view.paint(g2);
                for (JComponent jComp : originalDoubleBuffered) {
                    jComp.setDoubleBuffered(true);
                }
                originalDoubleBuffered.clear();
                return;
            }
        }
        layer.paint(g2);
    }

    /**
     * Disable the double buffering for the {@code component} and for all of it's children
     * 
     * @param component
     */
    private void setToNoDoubleBuffering(Component component) {
        if (component instanceof JComponent) {
            JComponent jComp = (JComponent) component;
            if (jComp.isDoubleBuffered()) {
                originalDoubleBuffered.add(jComp);
                jComp.setDoubleBuffered(false);
            }
        }
        if (component instanceof Container) {
            Container container = (Container) component;
            for (int index = 0; index < container.getComponentCount(); index++) {
                setToNoDoubleBuffering(container.getComponent(index));
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void uninstallUI(JComponent component) {
        if (!(component instanceof JLayer<?>)) {
            throw new IllegalArgumentException(
                    this.getClass().getName() + " invalid class, must be a JLayer component");
        }
        JLayer<JComponent> jlayer = (JLayer<JComponent>) component;
        jlayer.setLayerEventMask(0);
        super.uninstallUI(component);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void installUI(JComponent component) throws IllegalStateException {
        super.installUI(component);
        if (installedLayer != null) {
            throw new IllegalStateException(this.getClass().getName() + " cannot be shared between multiple layers");
        }
        if (!(component instanceof JLayer<?>)) {
            throw new IllegalArgumentException(
                    this.getClass().getName() + " invalid class, must be a JLayer component");
        }
        // component.getClass().getDeclaringClass();
        installedLayer = (JLayer<JComponent>) component;
        installedLayer.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK
                | AWTEvent.MOUSE_WHEEL_EVENT_MASK | AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
    }

    /**
     * Process the mouse events and map the mouse coordinates inverting the internal affine transformation.
     * It consume the original event, calculates the mapped mouse coordinates and find the real target of the mouse event.
     * It than create a new event with the correct informations in it and redispatch it to the target event
     * 
     * @param originalEvent the event to be dispatched
     * @param layer the layer this LayerUI is set to
     */
    private void redispatchMouseEvent(MouseEvent originalEvent, JLayer<? extends JComponent> layer) {
        if (layer.getView() != null) {
            if (originalEvent.getComponent() != layer.getGlassPane()) {
                originalEvent.consume();
            }
            MouseEvent newEvent = null;

            Point realPoint = calculateTargetPoint(layer, originalEvent);
            Component realTarget = getTarget(layer, realPoint);

            // Component realTarget =
            // SwingUtilities.getDeepestComponentAt(layer.getView(),
            // realPoint.x, realPoint.y);

            if (realTarget != null) {
                //System.out.println(realTarget.getClass().getName());
                realTarget = getListeningComponent(originalEvent, realTarget);
            }

            switch (originalEvent.getID()) {
            case MouseEvent.MOUSE_PRESSED:
                newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
                if (newEvent != null) {
                    lastPressedTarget = newEvent.getComponent();
                }
                break;
            case MouseEvent.MOUSE_RELEASED:
                newEvent = transformMouseEvent(layer, originalEvent, lastPressedTarget, realPoint);
                lastPressedTarget = null;
                break;
            case MouseEvent.MOUSE_CLICKED:
                newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
                lastPressedTarget = null;
                break;
            case MouseEvent.MOUSE_MOVED:
                newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
                generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
                break;
            case MouseEvent.MOUSE_ENTERED:
                generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
                break;
            case MouseEvent.MOUSE_EXITED:
                generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
                break;
            case MouseEvent.MOUSE_DRAGGED:
                newEvent = transformMouseEvent(layer, originalEvent, lastPressedTarget, realPoint);
                generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
                break;
            case (MouseEvent.MOUSE_WHEEL):
                // redispatchMouseWheelEvent((MouseWheelEvent) originalEvent,
                // realTarget, realPoint);
                newEvent = transformMouseWheelEvent(layer, (MouseWheelEvent) originalEvent, realTarget, realPoint);
                break;/**/
            }
            dispatchMouseEvent(newEvent);
        }
    }

    /**
     * Apply the inverse transformation to {@code point}
     * 
     * @param layer the layer this LayerUI is set to
     * @param point the starting point
     * @return the transformed point
     */
    private Point transformPoint(JLayer<? extends JComponent> layer, Point point) {
        if (transform != null) {
            try {
                transform.inverseTransform(point, point);
            } catch (NoninvertibleTransformException e) {
                e.printStackTrace();
            }
        }
        return point;
    }

    /**
     * Find the deepest component in the AWT hierarchy
     * 
     * @param layer  the layer to which this UI is installed
     * @param targetPoint the point in layer's coordinates
     * @return the component in the specified point
     */
    private Component getTarget(JLayer<? extends JComponent> layer, Point targetPoint) {
        Component view = layer.getView();
        if (view == null) {
            return null;
        } else {
            Point viewPoint = SwingUtilities.convertPoint(layer, targetPoint, view);
            return SwingUtilities.getDeepestComponentAt(view, viewPoint.x, viewPoint.y);
        }
    }

    /**
     * Convert the {@code mouseEvent}'s coordinates to the {@code layer}'s space
     * @param layer the layer this LayerUI is set to
     * @param mouseEvent the original mouse event
     * @return the {@code mouseEvent}'s point transformed to the {@code layer}'s coordinate space
     */
    private Point calculateTargetPoint(JLayer<? extends JComponent> layer,
            MouseEvent mouseEvent) {
        Point point = mouseEvent.getPoint();
        //SwingUtilities.convertPointToScreen(point, mouseEvent.getComponent());
        //SwingUtilities.convertPointFromScreen(point, layer);
        point = SwingUtilities.convertPoint(mouseEvent.getComponent(), point, layer);
        return transformPoint(layer, point);

        }

    private MouseEvent transformMouseEvent(JLayer<? extends JComponent> layer, MouseEvent mouseEvent, Component target, Point realPoint) {
        return transformMouseEvent( layer, mouseEvent, target, realPoint, mouseEvent.getID());
    }

    /**
     * Create the new event to being dispatched
     */
    private MouseEvent transformMouseEvent(JLayer<? extends JComponent> layer, MouseEvent mouseEvent, Component target, Point targetPoint, int id) {
        if (target == null) {
            return null;
        } else {
            Point newPoint = SwingUtilities.convertPoint(layer, targetPoint, target);
            return new MouseEvent(target, //
                    id, //
                    mouseEvent.getWhen(), //
                    mouseEvent.getModifiers(), //
                    newPoint.x, //
                    newPoint.y, //
                    mouseEvent.getClickCount(), //
                    mouseEvent.isPopupTrigger(), //
                    mouseEvent.getButton());
        }
    }

    /**
     * Create the new mouse wheel event to being dispached
     */
    private MouseWheelEvent transformMouseWheelEvent( JLayer<? extends JComponent> layer, MouseWheelEvent mouseWheelEvent, Component target,
            Point targetPoint) {
        if (target == null) {
            return null;
        } else {
            Point newPoint = SwingUtilities.convertPoint(layer, targetPoint, target);
            return new MouseWheelEvent(target, //
                    mouseWheelEvent.getID(), //
                    mouseWheelEvent.getWhen(), //
                    mouseWheelEvent.getModifiers(), //
                    newPoint.x, //
                    newPoint.y, //
                    mouseWheelEvent.getClickCount(), //
                    mouseWheelEvent.isPopupTrigger(), //
                    mouseWheelEvent.getScrollType(), //
                    mouseWheelEvent.getScrollAmount(), //
                    mouseWheelEvent.getWheelRotation() //
            );
        }
    }

    /**
     * dispatch the {@code mouseEvent}
     * @param mouseEvent the event to be dispatched
     */
    private void dispatchMouseEvent(MouseEvent mouseEvent) {
        if (mouseEvent != null) {
            Component target = mouseEvent.getComponent();
            target.dispatchEvent(mouseEvent);
        }
    }

    /**
     * Get the listening component associated to the {@code component}'s {@code event}
     */
    private Component getListeningComponent(MouseEvent event, Component component) {
        switch (event.getID()) {
        case (MouseEvent.MOUSE_CLICKED):
        case (MouseEvent.MOUSE_ENTERED):
        case (MouseEvent.MOUSE_EXITED):
        case (MouseEvent.MOUSE_PRESSED):
        case (MouseEvent.MOUSE_RELEASED):
            return getMouseListeningComponent(component);
        case (MouseEvent.MOUSE_DRAGGED):
        case (MouseEvent.MOUSE_MOVED):
            return getMouseMotionListeningComponent(component);
        case (MouseEvent.MOUSE_WHEEL):
            return getMouseWheelListeningComponent(component);
        }
        return null;
    }

    /**
     * Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseListener}
     */
    private Component getMouseListeningComponent(Component component) {
        if (component.getMouseListeners().length > 0) {
            return component;
        } else {
            Container parent = component.getParent();
            if (parent != null) {
                return getMouseListeningComponent(parent);
            } else {
                return null;
            }
        }
    }

    /**
     * Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseMotionListener}
     */
    private Component getMouseMotionListeningComponent(Component component) {
        /*
         * Mouse motion events may result in MOUSE_ENTERED and MOUSE_EXITED.
         * 
         * Therefore, components with MouseListeners registered should be
         * returned as well.
         */
        if (component.getMouseMotionListeners().length > 0 || component.getMouseListeners().length > 0) {
            return component;
        } else {
            Container parent = component.getParent();
            if (parent != null) {
                return getMouseMotionListeningComponent(parent);
            } else {
                return null;
            }
        }
    }

    /**
     * Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseWheelListener}
     */
    private Component getMouseWheelListeningComponent(Component component) {
        if (component.getMouseWheelListeners().length > 0) {
            return component;
        } else {
            Container parent = component.getParent();
            if (parent != null) {
                return getMouseWheelListeningComponent(parent);
            } else {
                return null;
            }
        }
    }

    /**
     * Generate a {@code MOUSE_ENTERED} and {@code MOUSE_EXITED} event when the target component is changed
     */
    private void generateEnterExitEvents( JLayer<? extends JComponent> layer,MouseEvent originalEvent, Component newTarget, Point realPoint) {
        if (lastEnteredTarget != newTarget) {
            dispatchMouseEvent(
                    transformMouseEvent(layer, originalEvent, lastEnteredTarget, realPoint, MouseEvent.MOUSE_EXITED));
            lastEnteredTarget = newTarget;
            //System.out.println("Last " + lastEnteredTarget.getClass().getName());
            dispatchMouseEvent(
                    transformMouseEvent(layer, originalEvent, lastEnteredTarget, realPoint, MouseEvent.MOUSE_ENTERED));
        }
    }
}

ZoomPanel是一个JPanel,其中包含一个JLayer,其中包含TransformUIJLayer包含JPanel SpringLayout,其中使用比例因子更新约束以正确布局组件(JXLayer拥有它LayoutManager JLayer 1}}但在package jzoom.transform; import ... public class ZoomPanel extends JPanel { private static final long serialVersionUID = 1L; private AffineTransform transform; private TransformUI layerUI; private JLayer<JComponent> layer; private SpringLayout layout; private JPanel springPanel; private Container view = null; public ZoomPanel() { this(null); } public ZoomPanel(Container view) { setLayout(new BorderLayout()); this.view = view; transform = new AffineTransform(); layout = new SpringLayout(); springPanel = new JPanel(layout); if (view != null) { updateConstraints(); springPanel.add(view); } layerUI = new TransformUI(); layerUI.setTransform(transform); layer = new JLayer<JComponent>(springPanel, layerUI); super.add(layer); } private void updateConstraints() { Spring width = layout.getConstraint(SpringLayout.WIDTH, springPanel); Spring height = layout.getConstraint(SpringLayout.HEIGHT, springPanel); SpringLayout.Constraints constraints = layout.getConstraints(view); constraints.setX(Spring.constant(0)); constraints.setY(Spring.constant(0)); constraints.setWidth(Spring.scale(width, (float) (1 / transform.getScaleX()))); constraints.setHeight(Spring.scale(height, (float) (1 / transform.getScaleX()))); } public void setView(Container view) { if (this.view != null) { throw new IllegalStateException( this.getClass().getName() + " cannot be shared between multiple containers"); } if (view != null) { this.view = view; updateConstraints(); springPanel.add(view); } else { throw new IllegalArgumentException("Can't set a null view"); } } public double getScale() { return transform.getScaleX(); } public void zoomIn() { setScale(transform.getScaleX() + 0.1); } public void zoomOut() { setScale(transform.getScaleX() - 0.1); } public void setScale(double scale) { if (!(scale < 1)) { transform.setToIdentity(); transform.scale(scale, scale); updateConstraints(); springPanel.updateUI(); } } protected Component addToView(Component comp, Object constraints, int index) { if (view != null) { view.add(comp, constraints, index); return comp; } if (comp instanceof Container) { setView((Container) comp); return view; } throw new IllegalStateException("You need to add or set a Container view before adding Components"); } @Override public Component add(Component comp) { // TODO Auto-generated method stub return addToView(comp, null, this.getComponentCount()); } @Override public Component add(Component comp, int index) { // TODO Auto-generated method stub return addToView(comp, null, index); } @Override public void add(Component comp, Object constraints) { // TODO Auto-generated method stub addToView(comp, constraints, this.getComponentCount()); } @Override public void add(Component comp, Object constraints, int index) { // TODO Auto-generated method stub addToView(comp, constraints, index); } private void inspectView(Container view) { PrintStream ps = null; try { ps = new PrintStream("C:\\Users\\andrea.maracci\\Documents\\sicraReflectionTemp.txt"); inspectView(view, 0, ps); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (ps != null) { ps.close(); } } } private static void inspectView(Component component, Integer level, PrintStream ps) { for (Integer i = 0; i < level; i++) { ps.print("\t"); } ps.print(level + ")"); ps.println("Inspecting " + component.getClass().getName()); int accessibleCount = 0; if (component.getAccessibleContext() != null) { accessibleCount = component.getAccessibleContext().getAccessibleChildrenCount(); if (accessibleCount > 0) { ps.println("*********************************************ACCESSIBLE CONTEXT*********************************************"); for (int i = 0; i < accessibleCount; i++) { ps.println(i + ") " + component.getAccessibleContext().getAccessibleChild(i).getClass().getName()); } ps.println("************************************************************************************************************"); } } if (component instanceof JComponent) { JComponent jComponent = ((JComponent)component); if (jComponent.getComponentCount() > 0) { Component[] children = jComponent.getComponents(); for (Component child : children) { inspectView(child, ++level, ps); } } } --level; } } 中你无法设置它)

package jzoom.test;

import ...

public class TestFinal {
    public static void main(String[] args) {
        new TestFinal();
    }

    public TestFinal() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (UnsupportedLookAndFeelException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setMinimumSize(new Dimension(400,500));
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JLayer<JComponent> layer;
        private TransformUI layerUI;
        private JPanel content;
        private AffineTransform transform = new AffineTransform();
        private ZoomPanel zoomPanel;

        public TestPane() {

            content = new JPanel(new GridBagLayout());
            // content = new JPanel(new XYLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridy = 0;
            gbc.weighty = 0;
            gbc.weightx = 0;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            JLabel label = new JLabel("Hello");
            JTextField field = new JTextField("World", 20);

            content.add(label, gbc);
            gbc.weightx = 1;
            content.add(field, gbc);
            // content.add(label, new XYConstraints(50, 20, 50, 22));
            // content.add(field, new XYConstraints(100, 20, 200, 22));

            gbc.gridy++;
            gbc.gridwidth = 2;

            final JSlider slider = new JSlider(100, 200);
            slider.setValue(100);
            slider.addChangeListener(new ChangeListener() {

                @Override
                public void stateChanged(ChangeEvent e) {
                    int value = slider.getValue();
                    double scale = value / 100d;
                    zoomPanel.setScale(scale);
                }
            });
            content.add(slider, gbc);
            // content.add(slider, new XYConstraints(75, 50, 200, 50));

            gbc.gridy++;
            gbc.gridwidth = 2;
            gbc.weighty = 1;
            gbc.fill = GridBagConstraints.BOTH;
            JTextArea textArea = new JTextArea();
            textArea.setEditable(true);
            textArea.setText(
                    "pollofritto\npalma\npalmipedone\ncaccoletta\namammata\na\nasd\nasdgfag\nasdafa\nasdfasf\nadsfasdf\nadfadsf\nadsfdasf\nasdfdas\npollofritto\npalma\npalmipedone\ncaccoletta\namammata\na\nasd\nasdgfag\nasdafa\nasdfasf\nadsfasdf\nadfadsf\nadsfdasf\nasdfdas");
            // textArea.setPreferredSize(new Dimensions());
            JScrollPane scrollPane = new JScrollPane(textArea);
            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            scrollPane.setPreferredSize(new Dimension(200, 75));
            content.add(scrollPane, gbc);

            gbc.gridy++;
            gbc.gridwidth = 2;
            gbc.weighty = 0;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            String[] petStrings = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
            JComboBox petList = new JComboBox(petStrings);
            content.add(petList, gbc);

            JButton zoomIn = new JButton("Zoom In");
            // zoomIn.addMouseListener(new ZoomMouseListener());
            zoomIn.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    // System.out.println("FIRST");
                    // layerUI.zoomIn();

                    //double zoom = transform.getScaleX();
                    //transform.setToIdentity();
                    //transform.scale(zoom + 0.1, zoom + 0.1);
                    zoomPanel.zoomIn();

                    // jLayer.repaint();
                }
            });

            JButton zoomOut = new JButton("Zoom Out");
            zoomOut.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    zoomPanel.zoomOut();

                    //double zoom = transform.getScaleX();
                    //transform.setToIdentity();
                    //transform.scale(zoom - 0.1, zoom - 0.1);
                    // jLayer.repaint();
                }
            });
            gbc.gridy++;
            gbc.gridx = 0;
            gbc.gridwidth = 0;
            gbc.anchor = GridBagConstraints.LINE_END;

            // content.add(zoomOut, new XYConstraints(50, 120, 100, 25));
            // content.add(zoomIn, new XYConstraints(170, 120, 100, 25));

            JPanel button = new JPanel();
            button.setLayout(new BoxLayout(button, BoxLayout.LINE_AXIS));
            button.add(zoomOut);
            button.add(zoomIn);
            gbc.fill = GridBagConstraints.NONE;
            content.add(button, gbc);

            setLayout(new BorderLayout());
            setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

            zoomPanel = new ZoomPanel();
            zoomPanel.setView(content);
            add(zoomPanel);
        }
    }
}

这是一个可怕的测试程序

import React, { CameraRoll } from 'react-native'