如何将JScroll栏添加到NavigableImagePanel,这是一个带有小导航视图的图像面板?

时间:2010-01-07 21:21:06

标签: java image swing jpanel jscrollpane

我有以下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>

1 个答案:

答案 0 :(得分:0)

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