Zooming in and zooming out within a panel

前端 未结 2 1194
小鲜肉
小鲜肉 2020-12-29 08:56

I have a Panel in which some 2D objects are moving about. I have overridden paintComponent() as necessary. Now I want to be able to zoom in and zoom out that area. When zoom

2条回答
  •  清歌不尽
    2020-12-29 09:39

    I know this question is old, but I thought I could post my solution in case it could be useful for someone in the future.

    So, I created a class that extends JPanel which implements the MouseWheelListener in order to detect when the user rolls the mouse. My class also listens for dragging in order to move the contents when the user clicks and drags.

    Code Explanation

    First, in the constructor you must set this as the MouseWheelListener

     addMouseWheelListener(this);
    

    For the zoom in and out I used a boolean zoomer (to indicate when the user rolls with the mouse) and two doubles zoomFactor (to keep the current factor by which the objects' sizes are multiplied) and prevZoomFactor (for the previous zoom factor).

    private double zoomFactor = 1;
    private double prevZoomFactor = 1;
    private boolean zoomer;
    

    I also override the paint() method of the JPanel, in which (before drawing anything) when the user zooms (zoomer=true) I scale the graphics by the zoomFactor. Code:

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2 = (Graphics2D) g;
        if (zoomer) {
            AffineTransform at = new AffineTransform();
            at.scale(zoomFactor, zoomFactor);
            prevZoomFactor = zoomFactor;
            g2.transform(at);
            zoomer = false;
        }
        // All drawings go here
    }
    

    Finally, I override the mouseWheelMoved method of the MouseWheelListener, in which I increase the zoomFactor (if the user rolls up) or decrease the zoomFactor (if the user rolls down). Code:

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
        zoomer = true;
        //Zoom in
        if (e.getWheelRotation() < 0) {
            zoomFactor *= 1.1;
            repaint();
        }
        //Zoom out
        if (e.getWheelRotation() > 0) {
            zoomFactor /= 1.1;
            repaint();
        }
    }
    

    Working Example

    If you also want to use the drag function and want to zoom according to the position of the mouse, you can use the class below, which gets a BufferedImage as a parameter in the constructor in order to display something on screen.

    I have also uploaded a project on GitHub called Zoomable-Java-Panel in which there is a functional example of what I showed above, which you can test and see how it can be implemented into a project.

    package zoomable.panel;
    
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.MouseInfo;
    import java.awt.Point;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.MouseMotionListener;
    import java.awt.event.MouseWheelEvent;
    import java.awt.event.MouseWheelListener;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import javax.swing.JPanel;
    
    /**
     *
     * @author Thanasis1101
     * @version 1.0
     */
    public class MainPanel extends JPanel implements MouseWheelListener, MouseListener, MouseMotionListener {
    
        private final BufferedImage image;
    
        private double zoomFactor = 1;
        private double prevZoomFactor = 1;
        private boolean zoomer;
        private boolean dragger;
        private boolean released;
        private double xOffset = 0;
        private double yOffset = 0;
        private int xDiff;
        private int yDiff;
        private Point startPoint;
    
        public MainPanel(BufferedImage image) {
    
            this.image = image;
            initComponent();
    
        }
    
        private void initComponent() {
            addMouseWheelListener(this);
            addMouseMotionListener(this);
            addMouseListener(this);
        }
    
        @Override
        public void paint(Graphics g) {
            super.paint(g);
    
            Graphics2D g2 = (Graphics2D) g;
    
            if (zoomer) {
                AffineTransform at = new AffineTransform();
    
                double xRel = MouseInfo.getPointerInfo().getLocation().getX() - getLocationOnScreen().getX();
                double yRel = MouseInfo.getPointerInfo().getLocation().getY() - getLocationOnScreen().getY();
    
                double zoomDiv = zoomFactor / prevZoomFactor;
    
                xOffset = (zoomDiv) * (xOffset) + (1 - zoomDiv) * xRel;
                yOffset = (zoomDiv) * (yOffset) + (1 - zoomDiv) * yRel;
    
                at.translate(xOffset, yOffset);
                at.scale(zoomFactor, zoomFactor);
                prevZoomFactor = zoomFactor;
                g2.transform(at);
                zoomer = false;
            }
    
            if (dragger) {
                AffineTransform at = new AffineTransform();
                at.translate(xOffset + xDiff, yOffset + yDiff);
                at.scale(zoomFactor, zoomFactor);
                g2.transform(at);
    
                if (released) {
                    xOffset += xDiff;
                    yOffset += yDiff;
                    dragger = false;
                }
    
            }
    
            // All drawings go here
    
            g2.drawImage(image, 0, 0, this);
    
        }
    
        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
    
            zoomer = true;
    
            //Zoom in
            if (e.getWheelRotation() < 0) {
                zoomFactor *= 1.1;
                repaint();
            }
            //Zoom out
            if (e.getWheelRotation() > 0) {
                zoomFactor /= 1.1;
                repaint();
            }
        }
    
        @Override
        public void mouseDragged(MouseEvent e) {
            Point curPoint = e.getLocationOnScreen();
            xDiff = curPoint.x - startPoint.x;
            yDiff = curPoint.y - startPoint.y;
    
            dragger = true;
            repaint();
    
        }
    
        @Override
        public void mouseMoved(MouseEvent e) {
        }
    
        @Override
        public void mouseClicked(MouseEvent e) {
    
        }
    
        @Override
        public void mousePressed(MouseEvent e) {
            released = false;
            startPoint = MouseInfo.getPointerInfo().getLocation();
        }
    
        @Override
        public void mouseReleased(MouseEvent e) {
            released = true;
            repaint();
        }
    
        @Override
        public void mouseEntered(MouseEvent e) {
    
        }
    
        @Override
        public void mouseExited(MouseEvent e) {
    
        }
    
    }
    

提交回复
热议问题