【问题标题】:Zooming in and zooming out within a panel在面板内放大和缩小
【发布时间】:2011-09-26 11:20:18
【问题描述】:

我有一个面板,其中一些 2D 对象正在移动。我已经根据需要覆盖了paintComponent()。现在我希望能够放大和缩小该区域。放大时,会出现滚动条,您可以通过滚动条查看整个字段。放大和缩小时,2D 对象的大小应相应增加或减小。哪个 Swing 组件或组件组合将有助于实现这一目标?

【问题讨论】:

    标签: java swing panel


    【解决方案1】:

    最简单的方法是修改您的面板并引入一个双倍来指示您的缩放级别。这个双精度表示您的比例,其中 1 是正常的,更高的会放大。您可以在 paintComponent 中使用该双精度和 Graphics2D

    如:

    Graphics2D g2 = (Graphics2D) g;
    int w = // real width of canvas
    int h = // real height of canvas
    // Translate used to make sure scale is centered
    g2.translate(w/2, h/2);
    g2.scale(scale, scale);
    g2.translate(-w/2, -h/2);
    

    对于滚动,将您的面板放在 JScrollPane 中,并将其与也使用缩放比例的 getPreferredSize 结合起来。 JScrollPane 使用您放入其中的组件的首选大小。如果首选大小超过自己的大小,它将显示滚动条。

    如果您更改面板的首选大小,以便缩放它返回的宽度和高度,您应该没问题。基本上你可以返回类似的东西:

    return new Dimension(w * scale, h * scale)
    

    【讨论】:

    • 谢谢。您能否解释一下您的意思:-“并将其与也使用您的缩放比例的 getPreferredSize 结合起来。”
    • 好的。所以首先我需要一个 JPanel,里面有一个 paintComponent() 方法。在paintComponent() 中,我将使用graphics2D 和一个double 来保持缩放级别。我还需要将双精度值与一些事件处理机制相关联,例如鼠标滚轮或按下缩放按钮。并且随着缩放值的增加或减少,面板的 getPreferredSize 将相应地向 JScrollPane 返回不同的值,JScrollPane 将相应地完成其工作。还要别的吗?非常感谢。
    【解决方案2】:

    我知道这个问题很老,但我想我可以发布我的解决方案,以防将来对某人有用。

    所以,我创建了一个扩展 JPanel 的类,该类实现了 MouseWheelListener,以便检测用户何时滚动鼠标。我的班级还监听拖动,以便在用户单击和拖动时移动内容。

    代码说明

    首先,在构造函数中,您必须将其设置为 MouseWheelListener

     addMouseWheelListener(this);
    

    对于放大和缩小,我使用了布尔值 zoomer(表示用户何时使用鼠标滚动)和两个双精度值 zoomFactor(保持当前乘以对象大小的因子)和 @ 987654325@(用于上一个缩放系数)。

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

    我还覆盖了 JPanel 的 paint() 方法,其中(在绘制任何内容之前)当用户缩放 (zoomer=true) 时,我通过 zoomFactor 缩放图形。代码:

    @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
    }
    

    最后,我重写了 MouseWheelListener 的 mouseWheelMoved 方法,在该方法中我增加了 zoomFactor(如果用户滚动)或减少 zoomFactor(如果用户滚动)。代码:

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

    工作示例

    如果你也想使用拖动功能,想根据鼠标的位置进行缩放,可以使用下面的类,它在构造函数中获取一个BufferedImage作为参数,以便在屏幕上显示一些东西。

    我还在 GitHub 上上传了一个名为 Zoomable-Java-Panel 的项目,其中有一个我上面展示的功能示例,您可以对其进行测试并了解如何将其实施到项目中。

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

    【讨论】:

    • 您永远不需要覆盖paint()。改写paintComponent()。在大多数情况下,效果是一样的。当您有一个不透明的面板或向面板添加小部件时,它会变得很糟糕。
    猜你喜欢
    • 2014-09-09
    • 1970-01-01
    • 2013-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 2022-10-24
    相关资源
    最近更新 更多