如何使该面板向面板中间缩放? [英] How do I make this panel zoom toward the middle of the panel?

查看:33
本文介绍了如何使该面板向面板中间缩放?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有代码的JPanel.当我用鼠标滚轮滚动时,我希望面板朝着面板中间的位置放大.当前,每当我用鼠标滚轮放大/缩小时,图像左上方的角都停留在同一位置.我很难找到正确的算法.

I have a JPanel with the code here. I want the panel to zoom in towards the center of what's in the panel when I scroll with the mousewheel. Currently, whenever I zoom in/out with the mouse wheel, the corner in the top left of the image stays in the same place. I've had a difficult time finding a correct algorithm.

要放大图片,代码使用AffineTransform对象,该对象根据双精度值缩放图像,该值根据鼠标滚轮的移动而增大或减小.

To zoom into the picture, the code uses an AffineTransform object which scales the image according to a double value which increases or decreases based on the movement of the mouse wheel.

还增加了复杂性的是,还可以在面板上单击和拖动图像.如果单击并拖动它,则缩放必须仍然放大面板中心的内容,而不是实际图像的中心.

What also adds to the complexity is that the image can also be clicked and dragged around the panel. If it is clicked and dragged, the zoom must still zoom in on what's in the center of the PANEL, and not the center of the actual image necessarily.

再一次,应该相对于当前可见区域的中心点进行缩放.也就是说,在发生缩放时,视图中心的点应保持固定.

Once again, the zooming should be done relative to the center point of the currently visible area. That is, as zooming occurs, the point at the center of the view should remain fixed.

这是代码(及其可执行文件):

This is the code (and it's executable):

package clientgui;

import java.awt.*;

import javax.imageio.ImageIO;
import javax.swing.*;

import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.swing.border.TitledBorder;

public class MoveImageExample extends JFrame {
    ShowCanvas canvas;

    public MoveImageExample() throws Exception {
        super();
        Container container = getContentPane();
        canvas = new ShowCanvas(
                "http://cdn.smosh.com/sites/default/files/bloguploads/funny-iphone-5-bruce-lee.jpg");
        container.setPreferredSize(new Dimension(canvas.getWidth(), canvas
                .getHeight()));
        System.out.println("width = " + canvas.getWidth() + " height = "
                + canvas.getHeight());
        container.add(canvas);
        pack();
        setVisible(true);
    }

    public static void main(String arg[]) throws Exception {
        new MoveImageExample();
    }
}

@SuppressWarnings("serial")
class ShowCanvas extends JPanel {
    int imageX = 0, imageY = 0;
    int lastMouseX = 0, lastMouseY = 0;
    int centerX = 225;
    int centerY = 225;
    int canvasWidth = 450;
    int canvasHeight = 450;
    double scaleFactor = 1.0;
    boolean firstMouseDrag = true;
    BufferedImage image;

    public ShowCanvas(String imagePath) throws Exception {
        setBackground(Color.white);
        MouseMotionHandler mouseHandler = new MouseMotionHandler();
        addMouseMotionListener(mouseHandler);
        addMouseListener(mouseHandler);
        addMouseWheelListener(mouseHandler);
        URL url = new URL(imagePath);
        Image rawImage = ImageIO.read(url);
        image = new BufferedImage(rawImage.getWidth(this),
                rawImage.getHeight(this), BufferedImage.TYPE_INT_ARGB);
        setSize(image.getWidth(), image.getHeight());
        Graphics2D g2 = image.createGraphics();
        g2.drawImage(rawImage, imageX, imageY, this);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2D = (Graphics2D) g;
        g2D.setColor(Color.gray);
        g.fillRect(0, 0, image.getWidth(), image.getHeight());
        AffineTransform transformer = new AffineTransform();
        // translate the image back (using new scale factor)
        transformer.scale(scaleFactor, scaleFactor); // scale by 2x on x and y
                                                        // axes.
        transformer.translate(imageX / scaleFactor, imageY / scaleFactor);
        g2D.drawImage(image, transformer, this);
    }

    class MouseMotionHandler extends MouseMotionAdapter implements
            MouseListener, MouseWheelListener {
        public void mousePressed(MouseEvent e) {
            lastMouseX = e.getX();
            lastMouseY = e.getY();
        }

        public void mouseDragged(MouseEvent e) {
            int xDiff = e.getX() - lastMouseX;
            int yDiff = e.getY() - lastMouseY;
            imageX = imageX + xDiff;
            imageY = imageY + yDiff;
            lastMouseX = e.getX();
            lastMouseY = e.getY();
            repaint();
        }

        public void mouseWheelMoved(MouseWheelEvent e) {
            int notches = e.getWheelRotation();
            scaleFactor = scaleFactor + notches / 10.0;
            if (scaleFactor < 0.5) {
                scaleFactor = 0.5;
            } else if (scaleFactor > 3.0) {
                scaleFactor = 3.0;
            }
            repaint();
        }

        public void mouseReleased(MouseEvent e) {
        }

        public void mouseEntered(MouseEvent e) {
        }

        public void mouseExited(MouseEvent e) {
        }

        public void mouseClicked(MouseEvent e) {
        }
    }
}

推荐答案

因此,基本思想是,当您更改比例尺时,而不是允许将整个更改添加/减去宽度/高度时,您需要在位置和大小之间进行划分...

So, the basic idea, is when you change the scale, rather then allowing the entire change to be added/subtracted from the width/height, you need to divide it between the location and the size...

public void mouseWheelMoved(MouseWheelEvent e) {
    int notches = e.getWheelRotation();

    // Get the current/old size...    
    double oldWidth = image.getWidth() * scaleFactor;
    double oldHeight = image.getHeight() * scaleFactor;

    scaleFactor = scaleFactor + notches / 10.0;
    if (scaleFactor < 0.5) {
        scaleFactor = 0.5;
    } else if (scaleFactor > 3.0) {
        scaleFactor = 3.0;
    }
    // Get the new size
    double newWidth = image.getWidth() * scaleFactor;
    double newHeight = image.getHeight() * scaleFactor;

    // Calculate the difference (and divide it by 2)
    double difWidth = (oldWidth - newWidth) / 2;
    double difHeight = (oldHeight - newHeight) / 2;

    // Add it to the image position...
    imageX += difWidth;
    imageY += difHeight;

    revalidate();
    repaint();
}

已更新了工作示例

好的,所以基本思想是要处理图像所在的虚拟空间.该虚拟空间具有一个大小(组件大小x比例因子).这使您可以将虚拟空间置于实际空间的中心.

Okay, so the basic idea is you're dealing with a virtual space, where the image sits. This virtual space has a size (the component size x the scale factor). This allows you to center the virtual space within the actual space.

之后,您只需要计算虚拟空间(在真实空间内)的x/y偏移量和图像的虚拟位置即可.

After that, you simply need to calculate the x/y offset of the virtual space (within the real space) and the virtual location of the image.

在此示例中,我删除了 AffineTransformation#setLocation ,以便生成图像的缩放实例,它只是使放置图像更加容易.

In this example, I removed the AffineTransformation#setLocation in favor of generating a scaled instance of the image, it simply made it easier to place the image.

import java.awt.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.net.URL;

public class MoveImageExample extends JFrame {

    ShowCanvas canvas;

    public MoveImageExample() throws Exception {
        super();
        Container container = getContentPane();
        canvas = new ShowCanvas(
                        "http://cdn.smosh.com/sites/default/files/bloguploads/funny-iphone-5-bruce-lee.jpg");
        container.add(canvas);
        pack();
        setVisible(true);
    }

    public static void main(String arg[]) throws Exception {
        new MoveImageExample();
    }

}

@SuppressWarnings("serial")
final class ShowCanvas extends JPanel {

    int imageX = 0, imageY = 0;
    int lastMouseX = 0, lastMouseY = 0;
    int centerX = 225;
    int centerY = 225;
    int canvasWidth = 450;
    int canvasHeight = 450;
    double scaleFactor = 1.0;
    boolean firstMouseDrag = true;
    BufferedImage image;
    private BufferedImage scaled;

    public ShowCanvas(String imagePath) throws Exception {
        setBackground(Color.white);
        MouseMotionHandler mouseHandler = new MouseMotionHandler();
        addMouseMotionListener(mouseHandler);
        addMouseListener(mouseHandler);
        addMouseWheelListener(mouseHandler);
        URL url = new URL(imagePath);
        Image rawImage = ImageIO.read(url);
        image = new BufferedImage(rawImage.getWidth(this),
                        rawImage.getHeight(this), BufferedImage.TYPE_INT_ARGB);
        setSize(image.getWidth(), image.getHeight());
        Graphics2D g2 = image.createGraphics();
        g2.drawImage(rawImage, imageX, imageY, this);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension((int) (image.getWidth()), (int) (image.getHeight()));
    }

    protected BufferedImage getScaledInstance() {
        if (scaled == null) {
            int width = (int) (image.getWidth() * scaleFactor);
            int height = (int) (image.getHeight() * scaleFactor);
            scaled = new BufferedImage(width, height, image.getType());
            Graphics2D g2d = scaled.createGraphics();
            AffineTransform transformer = new AffineTransform();
            transformer.scale(scaleFactor, scaleFactor); // scale by 2x on x and y
            g2d.setTransform(transformer);
            g2d.drawImage(image, 0, 0, this);
            g2d.dispose();
        }
        return scaled;
    }

    public Dimension getVirtualSize() {
        return new Dimension(
                        (int)(getWidth() * scaleFactor), 
                        (int)(getHeight() * scaleFactor));
    }

    public Point getVirtualPoint(int x, int y) {
        return new Point(
                        (int)(x * scaleFactor),
                        (int)(y * scaleFactor));
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Dimension vitualSize = getVirtualSize();
        int xOffset = (getWidth() - vitualSize.width) / 2;
        int yOffset = (getHeight() - vitualSize.height) / 2;

        Graphics2D g2D = (Graphics2D) g.create();
        g2D.setColor(Color.gray);
        g.fillRect(0, 0, image.getWidth(), image.getHeight());

        g2D.setColor(Color.GREEN);
        g2D.drawRect(xOffset, yOffset, vitualSize.width, vitualSize.height);
        g2D.setColor(Color.RED);
        g2D.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
        g2D.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);

        Point virtualPoint = getVirtualPoint(imageX, imageY);
        System.out.println(virtualPoint);
        g2D.drawImage(getScaledInstance(), virtualPoint.x + xOffset, virtualPoint.y + yOffset, this);
        g2D.dispose();
    }

    class MouseMotionHandler extends MouseMotionAdapter implements
                    MouseListener, MouseWheelListener {

        public void mousePressed(MouseEvent e) {
            lastMouseX = e.getX();
            lastMouseY = e.getY();
        }

        public void mouseDragged(MouseEvent e) {
            int xDiff = e.getX() - lastMouseX;
            int yDiff = e.getY() - lastMouseY;
            imageX = imageX + xDiff;
            imageY = imageY + yDiff;
            lastMouseX = e.getX();
            lastMouseY = e.getY();
            repaint();
        }

        public void mouseWheelMoved(MouseWheelEvent e) {
            scaled = null;
            int notches = e.getWheelRotation();

            scaleFactor = scaleFactor + notches / 10.0;
            if (scaleFactor < 0.5) {
                scaleFactor = 0.5;
            } else if (scaleFactor > 3.0) {
                scaleFactor = 3.0;
            }

            repaint();
        }

        public void mouseReleased(MouseEvent e) {
        }

        public void mouseEntered(MouseEvent e) {
        }

        public void mouseExited(MouseEvent e) {
        }

        public void mouseClicked(MouseEvent e) {
        }

    }

}

这篇关于如何使该面板向面板中间缩放?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆