如何将 JScroll 栏添加到 NavigableImagePanel(带有小型导航视图的图像面板)?

发布于 2024-08-17 03:34:02 字数 27430 浏览 9 评论 0原文

我有以下 NavigableImagePanel,它是在 BSD 许可下的,我在网上找到了它。我想要对该面板执行的操作如下:

我想向其中添加一个 JScrollPane,以便以完整尺寸显示图像,并让用户使用小导航面板重新居中图像。现在,面板会调整图像大小以适合当前面板尺寸。我希望它以实际大小加载图像,并让用户使用导航面板导航到图像的不同部分。

面板源代码:

            import java.awt.AWTEvent;
            import java.awt.BorderLayout;
            import java.awt.Color;
            import java.awt.Dimension;
            import java.awt.Graphics;
            import java.awt.Graphics2D;
            import java.awt.GraphicsEnvironment;
            import java.awt.Image;
            import java.awt.Point;
            import java.awt.Rectangle;
            import java.awt.RenderingHints;
            import java.awt.Toolkit;
            import java.awt.event.ComponentAdapter;
            import java.awt.event.ComponentEvent;
            import java.awt.event.MouseAdapter;
            import java.awt.event.MouseEvent;
            import java.awt.event.MouseMotionListener;
            import java.awt.event.MouseWheelEvent;
            import java.awt.event.MouseWheelListener;
            import java.awt.image.BufferedImage;
            import java.io.File;
            import java.io.IOException;
            import java.util.Arrays;
            import javax.imageio.ImageIO;
            import javax.swing.JFrame;
            import javax.swing.JOptionPane;
            import javax.swing.JPanel;
            import javax.swing.SwingUtilities;


    /**
     * @author pxt
     *
     */


    public class NavigableImagePanel extends JPanel {

            /**
             * <p>Identifies a change to the zoom level.</p>
             */
            public static final String ZOOM_LEVEL_CHANGED_PROPERTY = "zoomLevel";

            /**
             * <p>Identifies a change to the zoom increment.</p>
             */
            public static final String ZOOM_INCREMENT_CHANGED_PROPERTY = "zoomIncrement";

            /**
             * <p>Identifies that the image in the panel has changed.</p>
             */
            public static final String IMAGE_CHANGED_PROPERTY = "image";

            private static final double SCREEN_NAV_IMAGE_FACTOR = 0.15; // 15% of panel's width
            private static final double NAV_IMAGE_FACTOR = 0.3; // 30% of panel's width
            private static final double HIGH_QUALITY_RENDERING_SCALE_THRESHOLD = 1.0;
            private static final Object INTERPOLATION_TYPE =
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR;

            private double zoomIncrement = 0.2;
            private double zoomFactor = 1.0 + zoomIncrement;
            private double navZoomFactor = 1.0 + zoomIncrement;
            private BufferedImage image;
            private BufferedImage navigationImage;
            private int navImageWidth;
            private int navImageHeight;
            private double initialScale = 0.0;
            private double scale = 0.0;
            private double navScale = 0.0;
            private int originX = 0;
            private int originY = 0;
            private Point mousePosition;
            private Dimension previousPanelSize;
            private boolean navigationImageEnabled = true;
            private boolean highQualityRenderingEnabled = true;

            private WheelZoomDevice wheelZoomDevice = null;
            private ButtonZoomDevice buttonZoomDevice = null;

            /**
             * <p>Defines zoom devices.</p>
             */
            public static class ZoomDevice {
                    /**
                     * <p>Identifies that the panel does not implement zooming,
                     * but the component using the panel does (programmatic zooming method).</p>
                     */
                    public static final ZoomDevice NONE = new ZoomDevice("none");

                    /**
                     * <p>Identifies the left and right mouse buttons as the zooming device.</p>
                     */
                    public static final ZoomDevice MOUSE_BUTTON = new ZoomDevice("mouseButton");

                    /**
                     * <p>Identifies the mouse scroll wheel as the zooming device.</p>
                     */
                    public static final ZoomDevice MOUSE_WHEEL = new ZoomDevice("mouseWheel");

                    private String zoomDevice;
                    private ZoomDevice(String zoomDevice) {
                            this.zoomDevice = zoomDevice;
                    }
                    public String toString() {
                            return zoomDevice;
                    }
            }

            //This class is required for high precision image coordinates translation.
            private class Coords {
                    public double x;
                    public double y;
                    public Coords(double x, double y) {
                            this.x = x;
                            this.y = y;
                            }
                    public int getIntX() {
                            return (int)Math.round(x);
                    }
                    public int getIntY() {
                            return (int)Math.round(y);
                    }
                    public String toString() {
                            return "[Coords: x=" + x + ",y=" + y + "]";
                    }
            }

            private class WheelZoomDevice implements MouseWheelListener {
                    public void mouseWheelMoved(MouseWheelEvent e) {
                            Point p = e.getPoint();
                            boolean zoomIn = (e.getWheelRotation() < 0);
                            if (isInNavigationImage(p)) {
                                    if (zoomIn) {
                                            navZoomFactor = 1.0 + zoomIncrement;
                                    } else {
                                            navZoomFactor = 1.0 - zoomIncrement;
                                    }
                                    zoomNavigationImage();
                            } else if (isInImage(p)) {
                                    if (zoomIn) {
                                            zoomFactor = 1.0 + zoomIncrement;
                                    } else {
                                            zoomFactor = 1.0 - zoomIncrement;
                                    }
                                    zoomImage();
                            }
                    }
            }

            private class ButtonZoomDevice extends MouseAdapter {

                    public void mouseClicked(MouseEvent e) {

                            Point p = e.getPoint();
                            if (SwingUtilities.isRightMouseButton(e)) {
                                    if (isInNavigationImage(p)) {
                                            navZoomFactor = 1.0 - zoomIncrement;
                                            zoomNavigationImage();
                                    } else if (isInImage(p)) {
                                            zoomFactor = 1.0 - zoomIncrement;
                                            zoomImage();
                                    }
                            } else {
                                    if (isInNavigationImage(p)) {
                                            navZoomFactor = 1.0 + zoomIncrement;
                                            zoomNavigationImage();
                                    } else if (isInImage(p)) {
                                            zoomFactor = 1.0 + zoomIncrement;
                                            zoomImage();
                                    }
                            }
                    }

            }

            /**
             * <p>Creates a new navigable image panel with no default image and
             * the mouse scroll wheel as the zooming device.</p>
             */
            public NavigableImagePanel() {

                setOpaque(false);
                    addComponentListener(new ComponentAdapter() {
                            public void componentResized(ComponentEvent e) {
                                    if (scale > 0.0) {
                                            if (isFullImageInPanel()) {
                                                    centerImage();
                                            } else if (isImageEdgeInPanel()) {
                                                    scaleOrigin();
                                            }
                                            if (isNavigationImageEnabled()) {
                                                    createNavigationImage();
                                            }
                                            repaint();
                                    }
                                    previousPanelSize = getSize();
                            }
                    });

                    addMouseListener(new MouseAdapter() {
                            public void mousePressed(MouseEvent e) {
                                    if (SwingUtilities.isLeftMouseButton(e)) {
                                            if (isInNavigationImage(e.getPoint())) {
                                                    Point p = e.getPoint();
                                                    displayImageAt(p);
                                            }
                                    }
                            }
                            public void mouseClicked(MouseEvent e){
                                    if (e.getClickCount() == 2)  {
                                    resetImage();
                                    }
                            }
                    });

                    addMouseMotionListener(new MouseMotionListener() {
                            public void mouseDragged(MouseEvent e) {
                                    if (SwingUtilities.isLeftMouseButton(e)
                                            && !isInNavigationImage(e.getPoint())) {
                                            Point p = e.getPoint();
                                            moveImage(p);
                                    }
                            }
                            public void mouseMoved(MouseEvent e) {
                                    //we need the mouse position so that after zooming
                                    //that position of the image is maintained
                                    mousePosition = e.getPoint();
                            }
                    });

                    setZoomDevice(ZoomDevice.MOUSE_WHEEL);
            }

            /**
             * <p>Creates a new navigable image panel with the specified image
             * and the mouse scroll wheel as the zooming device.</p>
             */
            public NavigableImagePanel(BufferedImage image) throws IOException {
                    this();
                    setImage(image);
            }

            private void addWheelZoomDevice() {
                    if (wheelZoomDevice == null) {
                            wheelZoomDevice = new WheelZoomDevice();
                            addMouseWheelListener(wheelZoomDevice);
                    }
            }

            private void addButtonZoomDevice() {
                    if (buttonZoomDevice == null) {
                            buttonZoomDevice = new ButtonZoomDevice();
                            addMouseListener(buttonZoomDevice);
                    }
            }

            private void removeWheelZoomDevice() {
                    if (wheelZoomDevice != null) {
                            removeMouseWheelListener(wheelZoomDevice);
                            wheelZoomDevice = null;
                    }
            }

            private void removeButtonZoomDevice() {
                    if (buttonZoomDevice != null) {
                            removeMouseListener(buttonZoomDevice);
                            buttonZoomDevice = null;
                    }
            }

            /**
             * <p>Sets a new zoom device.</p>
             *
             * @param newZoomDevice specifies the type of a new zoom device.
             */
            public void setZoomDevice(ZoomDevice newZoomDevice) {
                    if (newZoomDevice == ZoomDevice.NONE) {
                            removeWheelZoomDevice();
                            removeButtonZoomDevice();
                    } else if (newZoomDevice == ZoomDevice.MOUSE_BUTTON) {
                            removeWheelZoomDevice();
                            addButtonZoomDevice();
                    } else if (newZoomDevice == ZoomDevice.MOUSE_WHEEL) {
                            removeButtonZoomDevice();
                            addWheelZoomDevice();
                    }
            }

            /**
             * <p>Gets the current zoom device.</p>
             */
            public ZoomDevice getZoomDevice() {
                    if (buttonZoomDevice != null) {
                            return ZoomDevice.MOUSE_BUTTON;
                    } else if (wheelZoomDevice != null) {
                            return ZoomDevice.MOUSE_WHEEL;
                    } else {
                            return ZoomDevice.NONE;
                    }
            }

            //Called from paintComponent() when a new image is set.
            private void initializeParams() {
                    double xScale = (double)getWidth() / image.getWidth();
                    double yScale = (double)getHeight() / image.getHeight();
                    initialScale = Math.min(xScale, yScale);
                    scale = initialScale;

                    //An image is initially centered
                    centerImage();
                    if (isNavigationImageEnabled()) {
                            createNavigationImage();
                    }
            }

            //Centers the current image in the panel.
            private void centerImage() {
                    originX = (int)(getWidth() - getScreenImageWidth()) / 2;
                    originY = (int)(getHeight() - getScreenImageHeight()) / 2;
            }

            //Creates and renders the navigation image in the upper let corner of the panel.
            private void createNavigationImage() {
                    //We keep the original navigation image larger than initially
                    //displayed to allow for zooming into it without pixellation effect.
                    navImageWidth = (int)(getWidth() * NAV_IMAGE_FACTOR);
                    navImageHeight = navImageWidth * image.getHeight() / image.getWidth();
                    int scrNavImageWidth = (int)(getWidth() * SCREEN_NAV_IMAGE_FACTOR);
                    int scrNavImageHeight = scrNavImageWidth * image.getHeight() / image.getWidth();
                    navScale = (double)scrNavImageWidth / navImageWidth;
                    navigationImage = new BufferedImage(navImageWidth, navImageHeight,
                            image.getType());
                    Graphics g = navigationImage.getGraphics();
                    g.drawImage(image, 0, 0, navImageWidth, navImageHeight, null);
            }

            /**
             * <p>Sets an image for display in the panel.</p>
             *
             * @param image an image to be set in the panel
             */
            public void setImage(BufferedImage image) {
                    BufferedImage oldImage = this.image;
                    this.image = image;
                    //Reset scale so that initializeParameters() is called in paintComponent()
                    //for the new image.
                    scale = 0.0;
                    firePropertyChange(IMAGE_CHANGED_PROPERTY, (Image)oldImage, (Image)image);
                    repaint();
            }

            /**
             * <p>resets an image to the centre of the panel</p>
             *
             */
            public void resetImage() {
                    BufferedImage oldImage = this.image;
                    this.image = image;
                    //Reset scale so that initializeParameters() is called in paintComponent()
                    //for the new image.
                    scale = 0.0;
                    firePropertyChange(IMAGE_CHANGED_PROPERTY, (Image)oldImage, (Image)image);
                    repaint();
            }

            /**
             * <p>Tests whether an image uses the standard RGB color space.</p>
             */
            public static boolean isStandardRGBImage(BufferedImage bImage) {
                    return bImage.getColorModel().getColorSpace().isCS_sRGB();
            }

            //Converts this panel's coordinates into the original image coordinates
            private Coords panelToImageCoords(Point p) {
                    return new Coords((p.x - originX) / scale, (p.y - originY) / scale);
            }

            //Converts the original image coordinates into this panel's coordinates
            private Coords imageToPanelCoords(Coords p) {
                    return new Coords((p.x * scale) + originX, (p.y * scale) + originY);
            }

            //Converts the navigation image coordinates into the zoomed image coordinates
            private Point navToZoomedImageCoords(Point p) {
                    int x = p.x * getScreenImageWidth() / getScreenNavImageWidth();
                    int y = p.y * getScreenImageHeight() / getScreenNavImageHeight();
                    return new Point(x, y);
            }

            //The user clicked within the navigation image and this part of the image
            //is displayed in the panel.
            //The clicked point of the image is centered in the panel.
            private void displayImageAt(Point p) {
                    Point scrImagePoint = navToZoomedImageCoords(p);
                    originX = -(scrImagePoint.x - getWidth() / 2);
                    originY = -(scrImagePoint.y - getHeight() / 2);
                    repaint();
            }

            //Tests whether a given point in the panel falls within the image boundaries.
            private boolean isInImage(Point p) {
                    Coords coords = panelToImageCoords(p);
                    int x = coords.getIntX();
                    int y = coords.getIntY();
                    return (x >= 0 && x < image.getWidth() && y >= 0 && y < image.getHeight());
            }

            //Tests whether a given point in the panel falls within the navigation image
            //boundaries.
            private boolean isInNavigationImage(Point p) {
                    return (isNavigationImageEnabled() && p.x < getScreenNavImageWidth()
                            && p.y < getScreenNavImageHeight());
            }

            //Used when the image is resized.
            private boolean isImageEdgeInPanel() {
                    if (previousPanelSize == null) {
                            return false;
                    }

                    return (originX > 0 && originX < previousPanelSize.width
                            || originY > 0 && originY < previousPanelSize.height);
            }

            //Tests whether the image is displayed in its entirety in the panel.
            private boolean isFullImageInPanel() {
                    return (originX >= 0 && (originX + getScreenImageWidth()) < getWidth()
                                    && originY >= 0 && (originY + getScreenImageHeight()) < getHeight());
            }

            /**
             * <p>Indicates whether the high quality rendering feature is enabled.</p>
             *
             * @return true if high quality rendering is enabled, false otherwise.
             */
            public boolean isHighQualityRenderingEnabled() {
                    return highQualityRenderingEnabled;
            }

            /**
             * <p>Enables/disables high quality rendering.</p>
             *
             * @param enabled enables/disables high quality rendering
             */
            public void setHighQualityRenderingEnabled(boolean enabled) {
                    highQualityRenderingEnabled = enabled;
            }

             //High quality rendering kicks in when when a scaled image is larger
             //than the original image. In other words,
             //when image decimation stops and interpolation starts.
            private boolean isHighQualityRendering() {
                    return (highQualityRenderingEnabled
                            && scale > HIGH_QUALITY_RENDERING_SCALE_THRESHOLD);
            }

            /**
             * <p>Indicates whether navigation image is enabled.<p>
             *
             * @return true when navigation image is enabled, false otherwise.
             */
            public boolean isNavigationImageEnabled() {
                    return navigationImageEnabled;
            }

            /**
             * <p>Enables/disables navigation with the navigation image.</p>
             * <p>Navigation image should be disabled when custom, programmatic navigation
             * is implemented.</p>
             *
             * @param enabled true when navigation image is enabled, false otherwise.
             */
            public void setNavigationImageEnabled(boolean enabled) {
                    navigationImageEnabled = enabled;
                    repaint();
            }

            //Used when the panel is resized
            private void scaleOrigin() {
                    originX = originX * getWidth() / previousPanelSize.width;
                    originY = originY * getHeight() / previousPanelSize.height;
                    repaint();
            }

            //Converts the specified zoom level to scale.
            private double zoomToScale(double zoom) {
                    return initialScale * zoom;
            }

            /**
             * <p>Gets the current zoom level.</p>
             *
             * @return the current zoom level
             */
            public double getZoom() {
                    return scale / initialScale;
            }

            /**
             * <p>Sets the zoom level used to display the image.</p>
             * <p>This method is used in programmatic zooming. The zooming center is
             * the point of the image closest to the center of the panel.
             * After a new zoom level is set the image is repainted.</p>
             *
             * @param newZoom the zoom level used to display this panel's image.
             */
            public void setZoom(double newZoom) {
                    Point zoomingCenter = new Point(getWidth() / 2, getHeight() / 2);
                    setZoom(newZoom, zoomingCenter);
            }

            /**
             * <p>Sets the zoom level used to display the image, and the zooming center,
             * around which zooming is done.</p>
             * <p>This method is used in programmatic zooming.
             * After a new zoom level is set the image is repainted.</p>
             *
             * @param newZoom the zoom level used to display this panel's image.
             */
            public void setZoom(double newZoom, Point zoomingCenter) {
                    Coords imageP = panelToImageCoords(zoomingCenter);
                    if (imageP.x < 0.0) {
                            imageP.x = 0.0;
                    }
                    if (imageP.y < 0.0) {
                            imageP.y = 0.0;
                    }
                    if (imageP.x >= image.getWidth()) {
                            imageP.x = image.getWidth() - 1.0;
                    }
                    if (imageP.y >= image.getHeight()) {
                            imageP.y = image.getHeight() - 1.0;
                    }

                    Coords correctedP = imageToPanelCoords(imageP);
                    double oldZoom = getZoom();
                    scale = zoomToScale(newZoom);
                    Coords panelP = imageToPanelCoords(imageP);

                    originX += (correctedP.getIntX() - (int)panelP.x);
                    originY += (correctedP.getIntY() - (int)panelP.y);

                    firePropertyChange(ZOOM_LEVEL_CHANGED_PROPERTY, new Double(oldZoom),
                            new Double(getZoom()));

                    repaint();
            }

            /**
             * <p>Gets the current zoom increment.</p>
             *
             * @return the current zoom increment
             */
            public double getZoomIncrement() {
                    return zoomIncrement;
            }

            /**
             * <p>Sets a new zoom increment value.</p>
             *
             * @param newZoomIncrement new zoom increment value
             */
            public void setZoomIncrement(double newZoomIncrement) {
                    double oldZoomIncrement = zoomIncrement;
                    zoomIncrement = newZoomIncrement;
                    firePropertyChange(ZOOM_INCREMENT_CHANGED_PROPERTY,
                            new Double(oldZoomIncrement), new Double(zoomIncrement));
            }

            //Zooms an image in the panel by repainting it at the new zoom level.
            //The current mouse position is the zooming center.
            private void zoomImage() {
                    Coords imageP = panelToImageCoords(mousePosition);
                    double oldZoom = getZoom();
                    scale *= zoomFactor;
                    Coords panelP = imageToPanelCoords(imageP);

                    originX += (mousePosition.x - (int)panelP.x);
                    originY += (mousePosition.y - (int)panelP.y);

                    firePropertyChange(ZOOM_LEVEL_CHANGED_PROPERTY, new Double(oldZoom),
                            new Double(getZoom()));

                    repaint();
            }

            //Zooms the navigation image
            private void zoomNavigationImage() {
                    navScale *= navZoomFactor;
                    repaint();
            }

            /**
             * <p>Gets the image origin.</p>
             * <p>Image origin is defined as the upper, left corner of the image in
             * the panel's coordinate system.</p>
             * @return the point of the upper, left corner of the image in the panel's coordinates
             * system.
             */
            public Point getImageOrigin() {
                    return new Point(originX, originY);
            }

            /**
             * <p>Sets the image origin.</p>
             * <p>Image origin is defined as the upper, left corner of the image in
             * the panel's coordinate system. After a new origin is set, the image is repainted.
             * This method is used for programmatic image navigation.</p>

I have the following NavigableImagePanel, it is under BSD license and I found it in the web. What I want to do with this panel is as follow:

I want to add a JScrollPane to it in order to show images in their full size and let the users to re-center the image using the small navigation panel. Right now, the panel resize the images to fit them in the current panel size. I want it to load the image in its real size and let users to navigate to different parts of the image using the navigation panel.

Source code for the panel:

            import java.awt.AWTEvent;
            import java.awt.BorderLayout;
            import java.awt.Color;
            import java.awt.Dimension;
            import java.awt.Graphics;
            import java.awt.Graphics2D;
            import java.awt.GraphicsEnvironment;
            import java.awt.Image;
            import java.awt.Point;
            import java.awt.Rectangle;
            import java.awt.RenderingHints;
            import java.awt.Toolkit;
            import java.awt.event.ComponentAdapter;
            import java.awt.event.ComponentEvent;
            import java.awt.event.MouseAdapter;
            import java.awt.event.MouseEvent;
            import java.awt.event.MouseMotionListener;
            import java.awt.event.MouseWheelEvent;
            import java.awt.event.MouseWheelListener;
            import java.awt.image.BufferedImage;
            import java.io.File;
            import java.io.IOException;
            import java.util.Arrays;
            import javax.imageio.ImageIO;
            import javax.swing.JFrame;
            import javax.swing.JOptionPane;
            import javax.swing.JPanel;
            import javax.swing.SwingUtilities;


    /**
     * @author pxt
     *
     */


    public class NavigableImagePanel extends JPanel {

            /**
             * <p>Identifies a change to the zoom level.</p>
             */
            public static final String ZOOM_LEVEL_CHANGED_PROPERTY = "zoomLevel";

            /**
             * <p>Identifies a change to the zoom increment.</p>
             */
            public static final String ZOOM_INCREMENT_CHANGED_PROPERTY = "zoomIncrement";

            /**
             * <p>Identifies that the image in the panel has changed.</p>
             */
            public static final String IMAGE_CHANGED_PROPERTY = "image";

            private static final double SCREEN_NAV_IMAGE_FACTOR = 0.15; // 15% of panel's width
            private static final double NAV_IMAGE_FACTOR = 0.3; // 30% of panel's width
            private static final double HIGH_QUALITY_RENDERING_SCALE_THRESHOLD = 1.0;
            private static final Object INTERPOLATION_TYPE =
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR;

            private double zoomIncrement = 0.2;
            private double zoomFactor = 1.0 + zoomIncrement;
            private double navZoomFactor = 1.0 + zoomIncrement;
            private BufferedImage image;
            private BufferedImage navigationImage;
            private int navImageWidth;
            private int navImageHeight;
            private double initialScale = 0.0;
            private double scale = 0.0;
            private double navScale = 0.0;
            private int originX = 0;
            private int originY = 0;
            private Point mousePosition;
            private Dimension previousPanelSize;
            private boolean navigationImageEnabled = true;
            private boolean highQualityRenderingEnabled = true;

            private WheelZoomDevice wheelZoomDevice = null;
            private ButtonZoomDevice buttonZoomDevice = null;

            /**
             * <p>Defines zoom devices.</p>
             */
            public static class ZoomDevice {
                    /**
                     * <p>Identifies that the panel does not implement zooming,
                     * but the component using the panel does (programmatic zooming method).</p>
                     */
                    public static final ZoomDevice NONE = new ZoomDevice("none");

                    /**
                     * <p>Identifies the left and right mouse buttons as the zooming device.</p>
                     */
                    public static final ZoomDevice MOUSE_BUTTON = new ZoomDevice("mouseButton");

                    /**
                     * <p>Identifies the mouse scroll wheel as the zooming device.</p>
                     */
                    public static final ZoomDevice MOUSE_WHEEL = new ZoomDevice("mouseWheel");

                    private String zoomDevice;
                    private ZoomDevice(String zoomDevice) {
                            this.zoomDevice = zoomDevice;
                    }
                    public String toString() {
                            return zoomDevice;
                    }
            }

            //This class is required for high precision image coordinates translation.
            private class Coords {
                    public double x;
                    public double y;
                    public Coords(double x, double y) {
                            this.x = x;
                            this.y = y;
                            }
                    public int getIntX() {
                            return (int)Math.round(x);
                    }
                    public int getIntY() {
                            return (int)Math.round(y);
                    }
                    public String toString() {
                            return "[Coords: x=" + x + ",y=" + y + "]";
                    }
            }

            private class WheelZoomDevice implements MouseWheelListener {
                    public void mouseWheelMoved(MouseWheelEvent e) {
                            Point p = e.getPoint();
                            boolean zoomIn = (e.getWheelRotation() < 0);
                            if (isInNavigationImage(p)) {
                                    if (zoomIn) {
                                            navZoomFactor = 1.0 + zoomIncrement;
                                    } else {
                                            navZoomFactor = 1.0 - zoomIncrement;
                                    }
                                    zoomNavigationImage();
                            } else if (isInImage(p)) {
                                    if (zoomIn) {
                                            zoomFactor = 1.0 + zoomIncrement;
                                    } else {
                                            zoomFactor = 1.0 - zoomIncrement;
                                    }
                                    zoomImage();
                            }
                    }
            }

            private class ButtonZoomDevice extends MouseAdapter {

                    public void mouseClicked(MouseEvent e) {

                            Point p = e.getPoint();
                            if (SwingUtilities.isRightMouseButton(e)) {
                                    if (isInNavigationImage(p)) {
                                            navZoomFactor = 1.0 - zoomIncrement;
                                            zoomNavigationImage();
                                    } else if (isInImage(p)) {
                                            zoomFactor = 1.0 - zoomIncrement;
                                            zoomImage();
                                    }
                            } else {
                                    if (isInNavigationImage(p)) {
                                            navZoomFactor = 1.0 + zoomIncrement;
                                            zoomNavigationImage();
                                    } else if (isInImage(p)) {
                                            zoomFactor = 1.0 + zoomIncrement;
                                            zoomImage();
                                    }
                            }
                    }

            }

            /**
             * <p>Creates a new navigable image panel with no default image and
             * the mouse scroll wheel as the zooming device.</p>
             */
            public NavigableImagePanel() {

                setOpaque(false);
                    addComponentListener(new ComponentAdapter() {
                            public void componentResized(ComponentEvent e) {
                                    if (scale > 0.0) {
                                            if (isFullImageInPanel()) {
                                                    centerImage();
                                            } else if (isImageEdgeInPanel()) {
                                                    scaleOrigin();
                                            }
                                            if (isNavigationImageEnabled()) {
                                                    createNavigationImage();
                                            }
                                            repaint();
                                    }
                                    previousPanelSize = getSize();
                            }
                    });

                    addMouseListener(new MouseAdapter() {
                            public void mousePressed(MouseEvent e) {
                                    if (SwingUtilities.isLeftMouseButton(e)) {
                                            if (isInNavigationImage(e.getPoint())) {
                                                    Point p = e.getPoint();
                                                    displayImageAt(p);
                                            }
                                    }
                            }
                            public void mouseClicked(MouseEvent e){
                                    if (e.getClickCount() == 2)  {
                                    resetImage();
                                    }
                            }
                    });

                    addMouseMotionListener(new MouseMotionListener() {
                            public void mouseDragged(MouseEvent e) {
                                    if (SwingUtilities.isLeftMouseButton(e)
                                            && !isInNavigationImage(e.getPoint())) {
                                            Point p = e.getPoint();
                                            moveImage(p);
                                    }
                            }
                            public void mouseMoved(MouseEvent e) {
                                    //we need the mouse position so that after zooming
                                    //that position of the image is maintained
                                    mousePosition = e.getPoint();
                            }
                    });

                    setZoomDevice(ZoomDevice.MOUSE_WHEEL);
            }

            /**
             * <p>Creates a new navigable image panel with the specified image
             * and the mouse scroll wheel as the zooming device.</p>
             */
            public NavigableImagePanel(BufferedImage image) throws IOException {
                    this();
                    setImage(image);
            }

            private void addWheelZoomDevice() {
                    if (wheelZoomDevice == null) {
                            wheelZoomDevice = new WheelZoomDevice();
                            addMouseWheelListener(wheelZoomDevice);
                    }
            }

            private void addButtonZoomDevice() {
                    if (buttonZoomDevice == null) {
                            buttonZoomDevice = new ButtonZoomDevice();
                            addMouseListener(buttonZoomDevice);
                    }
            }

            private void removeWheelZoomDevice() {
                    if (wheelZoomDevice != null) {
                            removeMouseWheelListener(wheelZoomDevice);
                            wheelZoomDevice = null;
                    }
            }

            private void removeButtonZoomDevice() {
                    if (buttonZoomDevice != null) {
                            removeMouseListener(buttonZoomDevice);
                            buttonZoomDevice = null;
                    }
            }

            /**
             * <p>Sets a new zoom device.</p>
             *
             * @param newZoomDevice specifies the type of a new zoom device.
             */
            public void setZoomDevice(ZoomDevice newZoomDevice) {
                    if (newZoomDevice == ZoomDevice.NONE) {
                            removeWheelZoomDevice();
                            removeButtonZoomDevice();
                    } else if (newZoomDevice == ZoomDevice.MOUSE_BUTTON) {
                            removeWheelZoomDevice();
                            addButtonZoomDevice();
                    } else if (newZoomDevice == ZoomDevice.MOUSE_WHEEL) {
                            removeButtonZoomDevice();
                            addWheelZoomDevice();
                    }
            }

            /**
             * <p>Gets the current zoom device.</p>
             */
            public ZoomDevice getZoomDevice() {
                    if (buttonZoomDevice != null) {
                            return ZoomDevice.MOUSE_BUTTON;
                    } else if (wheelZoomDevice != null) {
                            return ZoomDevice.MOUSE_WHEEL;
                    } else {
                            return ZoomDevice.NONE;
                    }
            }

            //Called from paintComponent() when a new image is set.
            private void initializeParams() {
                    double xScale = (double)getWidth() / image.getWidth();
                    double yScale = (double)getHeight() / image.getHeight();
                    initialScale = Math.min(xScale, yScale);
                    scale = initialScale;

                    //An image is initially centered
                    centerImage();
                    if (isNavigationImageEnabled()) {
                            createNavigationImage();
                    }
            }

            //Centers the current image in the panel.
            private void centerImage() {
                    originX = (int)(getWidth() - getScreenImageWidth()) / 2;
                    originY = (int)(getHeight() - getScreenImageHeight()) / 2;
            }

            //Creates and renders the navigation image in the upper let corner of the panel.
            private void createNavigationImage() {
                    //We keep the original navigation image larger than initially
                    //displayed to allow for zooming into it without pixellation effect.
                    navImageWidth = (int)(getWidth() * NAV_IMAGE_FACTOR);
                    navImageHeight = navImageWidth * image.getHeight() / image.getWidth();
                    int scrNavImageWidth = (int)(getWidth() * SCREEN_NAV_IMAGE_FACTOR);
                    int scrNavImageHeight = scrNavImageWidth * image.getHeight() / image.getWidth();
                    navScale = (double)scrNavImageWidth / navImageWidth;
                    navigationImage = new BufferedImage(navImageWidth, navImageHeight,
                            image.getType());
                    Graphics g = navigationImage.getGraphics();
                    g.drawImage(image, 0, 0, navImageWidth, navImageHeight, null);
            }

            /**
             * <p>Sets an image for display in the panel.</p>
             *
             * @param image an image to be set in the panel
             */
            public void setImage(BufferedImage image) {
                    BufferedImage oldImage = this.image;
                    this.image = image;
                    //Reset scale so that initializeParameters() is called in paintComponent()
                    //for the new image.
                    scale = 0.0;
                    firePropertyChange(IMAGE_CHANGED_PROPERTY, (Image)oldImage, (Image)image);
                    repaint();
            }

            /**
             * <p>resets an image to the centre of the panel</p>
             *
             */
            public void resetImage() {
                    BufferedImage oldImage = this.image;
                    this.image = image;
                    //Reset scale so that initializeParameters() is called in paintComponent()
                    //for the new image.
                    scale = 0.0;
                    firePropertyChange(IMAGE_CHANGED_PROPERTY, (Image)oldImage, (Image)image);
                    repaint();
            }

            /**
             * <p>Tests whether an image uses the standard RGB color space.</p>
             */
            public static boolean isStandardRGBImage(BufferedImage bImage) {
                    return bImage.getColorModel().getColorSpace().isCS_sRGB();
            }

            //Converts this panel's coordinates into the original image coordinates
            private Coords panelToImageCoords(Point p) {
                    return new Coords((p.x - originX) / scale, (p.y - originY) / scale);
            }

            //Converts the original image coordinates into this panel's coordinates
            private Coords imageToPanelCoords(Coords p) {
                    return new Coords((p.x * scale) + originX, (p.y * scale) + originY);
            }

            //Converts the navigation image coordinates into the zoomed image coordinates
            private Point navToZoomedImageCoords(Point p) {
                    int x = p.x * getScreenImageWidth() / getScreenNavImageWidth();
                    int y = p.y * getScreenImageHeight() / getScreenNavImageHeight();
                    return new Point(x, y);
            }

            //The user clicked within the navigation image and this part of the image
            //is displayed in the panel.
            //The clicked point of the image is centered in the panel.
            private void displayImageAt(Point p) {
                    Point scrImagePoint = navToZoomedImageCoords(p);
                    originX = -(scrImagePoint.x - getWidth() / 2);
                    originY = -(scrImagePoint.y - getHeight() / 2);
                    repaint();
            }

            //Tests whether a given point in the panel falls within the image boundaries.
            private boolean isInImage(Point p) {
                    Coords coords = panelToImageCoords(p);
                    int x = coords.getIntX();
                    int y = coords.getIntY();
                    return (x >= 0 && x < image.getWidth() && y >= 0 && y < image.getHeight());
            }

            //Tests whether a given point in the panel falls within the navigation image
            //boundaries.
            private boolean isInNavigationImage(Point p) {
                    return (isNavigationImageEnabled() && p.x < getScreenNavImageWidth()
                            && p.y < getScreenNavImageHeight());
            }

            //Used when the image is resized.
            private boolean isImageEdgeInPanel() {
                    if (previousPanelSize == null) {
                            return false;
                    }

                    return (originX > 0 && originX < previousPanelSize.width
                            || originY > 0 && originY < previousPanelSize.height);
            }

            //Tests whether the image is displayed in its entirety in the panel.
            private boolean isFullImageInPanel() {
                    return (originX >= 0 && (originX + getScreenImageWidth()) < getWidth()
                                    && originY >= 0 && (originY + getScreenImageHeight()) < getHeight());
            }

            /**
             * <p>Indicates whether the high quality rendering feature is enabled.</p>
             *
             * @return true if high quality rendering is enabled, false otherwise.
             */
            public boolean isHighQualityRenderingEnabled() {
                    return highQualityRenderingEnabled;
            }

            /**
             * <p>Enables/disables high quality rendering.</p>
             *
             * @param enabled enables/disables high quality rendering
             */
            public void setHighQualityRenderingEnabled(boolean enabled) {
                    highQualityRenderingEnabled = enabled;
            }

             //High quality rendering kicks in when when a scaled image is larger
             //than the original image. In other words,
             //when image decimation stops and interpolation starts.
            private boolean isHighQualityRendering() {
                    return (highQualityRenderingEnabled
                            && scale > HIGH_QUALITY_RENDERING_SCALE_THRESHOLD);
            }

            /**
             * <p>Indicates whether navigation image is enabled.<p>
             *
             * @return true when navigation image is enabled, false otherwise.
             */
            public boolean isNavigationImageEnabled() {
                    return navigationImageEnabled;
            }

            /**
             * <p>Enables/disables navigation with the navigation image.</p>
             * <p>Navigation image should be disabled when custom, programmatic navigation
             * is implemented.</p>
             *
             * @param enabled true when navigation image is enabled, false otherwise.
             */
            public void setNavigationImageEnabled(boolean enabled) {
                    navigationImageEnabled = enabled;
                    repaint();
            }

            //Used when the panel is resized
            private void scaleOrigin() {
                    originX = originX * getWidth() / previousPanelSize.width;
                    originY = originY * getHeight() / previousPanelSize.height;
                    repaint();
            }

            //Converts the specified zoom level to scale.
            private double zoomToScale(double zoom) {
                    return initialScale * zoom;
            }

            /**
             * <p>Gets the current zoom level.</p>
             *
             * @return the current zoom level
             */
            public double getZoom() {
                    return scale / initialScale;
            }

            /**
             * <p>Sets the zoom level used to display the image.</p>
             * <p>This method is used in programmatic zooming. The zooming center is
             * the point of the image closest to the center of the panel.
             * After a new zoom level is set the image is repainted.</p>
             *
             * @param newZoom the zoom level used to display this panel's image.
             */
            public void setZoom(double newZoom) {
                    Point zoomingCenter = new Point(getWidth() / 2, getHeight() / 2);
                    setZoom(newZoom, zoomingCenter);
            }

            /**
             * <p>Sets the zoom level used to display the image, and the zooming center,
             * around which zooming is done.</p>
             * <p>This method is used in programmatic zooming.
             * After a new zoom level is set the image is repainted.</p>
             *
             * @param newZoom the zoom level used to display this panel's image.
             */
            public void setZoom(double newZoom, Point zoomingCenter) {
                    Coords imageP = panelToImageCoords(zoomingCenter);
                    if (imageP.x < 0.0) {
                            imageP.x = 0.0;
                    }
                    if (imageP.y < 0.0) {
                            imageP.y = 0.0;
                    }
                    if (imageP.x >= image.getWidth()) {
                            imageP.x = image.getWidth() - 1.0;
                    }
                    if (imageP.y >= image.getHeight()) {
                            imageP.y = image.getHeight() - 1.0;
                    }

                    Coords correctedP = imageToPanelCoords(imageP);
                    double oldZoom = getZoom();
                    scale = zoomToScale(newZoom);
                    Coords panelP = imageToPanelCoords(imageP);

                    originX += (correctedP.getIntX() - (int)panelP.x);
                    originY += (correctedP.getIntY() - (int)panelP.y);

                    firePropertyChange(ZOOM_LEVEL_CHANGED_PROPERTY, new Double(oldZoom),
                            new Double(getZoom()));

                    repaint();
            }

            /**
             * <p>Gets the current zoom increment.</p>
             *
             * @return the current zoom increment
             */
            public double getZoomIncrement() {
                    return zoomIncrement;
            }

            /**
             * <p>Sets a new zoom increment value.</p>
             *
             * @param newZoomIncrement new zoom increment value
             */
            public void setZoomIncrement(double newZoomIncrement) {
                    double oldZoomIncrement = zoomIncrement;
                    zoomIncrement = newZoomIncrement;
                    firePropertyChange(ZOOM_INCREMENT_CHANGED_PROPERTY,
                            new Double(oldZoomIncrement), new Double(zoomIncrement));
            }

            //Zooms an image in the panel by repainting it at the new zoom level.
            //The current mouse position is the zooming center.
            private void zoomImage() {
                    Coords imageP = panelToImageCoords(mousePosition);
                    double oldZoom = getZoom();
                    scale *= zoomFactor;
                    Coords panelP = imageToPanelCoords(imageP);

                    originX += (mousePosition.x - (int)panelP.x);
                    originY += (mousePosition.y - (int)panelP.y);

                    firePropertyChange(ZOOM_LEVEL_CHANGED_PROPERTY, new Double(oldZoom),
                            new Double(getZoom()));

                    repaint();
            }

            //Zooms the navigation image
            private void zoomNavigationImage() {
                    navScale *= navZoomFactor;
                    repaint();
            }

            /**
             * <p>Gets the image origin.</p>
             * <p>Image origin is defined as the upper, left corner of the image in
             * the panel's coordinate system.</p>
             * @return the point of the upper, left corner of the image in the panel's coordinates
             * system.
             */
            public Point getImageOrigin() {
                    return new Point(originX, originY);
            }

            /**
             * <p>Sets the image origin.</p>
             * <p>Image origin is defined as the upper, left corner of the image in
             * the panel's coordinate system. After a new origin is set, the image is repainted.
             * This method is used for programmatic image navigation.</p>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏末的微笑 2024-08-24 03:34:02

我之前就使用过这个组件,但从来没有按照你描述的方式使用过。代码中有一个现有函数 setZoom(),可用于以编程方式设置缩放级别并重新绘制图像。我建议您尝试该功能和缩放级别。

I've used this component before myself, but never in exactly the way you describe. There is an existing function in the code, setZoom(), that can be used to programatically set the zoom level and repaint the image. I would recommend that you experiment with that function and the zoom level.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文