如何初始化取决于组件大小的图像抓取?

时间:2014-06-14 17:06:49

标签: java image swing

我正在Java Swing中创建一个程序,但我遇到了一个问题。该程序有两个图像;其中一个图像是完整图像,它将显示在图像导航器中。另一个图像是整个图像的放大部分,并显示在另一个组件中。

每当要在ZoomedImage容器中查看的部分更新时,我的主类就会出现这样的事情:

BufferedImage zoom = imageNavigator.getZoomedImage();
((ZoomedImage)container.getTopComponent()).updatePanel(zoom);

调用:

public BufferedImage getZoomedImage(){
    BufferedImage img = image.getSubimage((int)(startX/scaleX), (int)(startY/scaleY), (int)(image.getWidth()*percentViewWidth), (int)(image.getHeight()*percentViewHeight));
    BufferedImage copyOfImage = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics g = copyOfImage.createGraphics();
    g.drawImage(img, 0, 0, null);
    return copyOfImage;
}

初始化组件时我也会调用类似的代码。

startX / Y是框的起点,显示了它放大的区域。 ScaleX / Y与要显示的图像大小和显示图像的组件大小之间的比例有关。 percentViewWidth / Height是缩放信息的一部分。

组件全部打包后,功能正常。每当我更改我正在查看的原始图像的哪个部分时,缩放的图像就会更新。问题是,为了做到这一点,我必须依赖于持有主图像的组件的大小,以便我可以抓取图像的正确部分。首次初始化时,大小为0,所以我无法获取正确的部分。如何在图像大小后立即更新图像?

1 个答案:

答案 0 :(得分:1)

如果我理解正确的问题,你的方法有点倒退。不要让ImageNavigator告诉ZoomedImage要绘制哪个子图像,让ZoomedImage在绘制时询问ImageNavigator(通过覆盖ZoomedImage的paintComponent方法)。当ZonedImage完成它的绘画时,它将完全布局在屏幕上并且知道它的大小,所以没有问题。

或者,让ZoomedImage维护整个图像和显示区域的坐标,这样它就可以获得绘制自身所需的完整信息。当用户与ImageNavigator交互时,它可以调用ZoomedImage来设置显示区域的坐标。

为了使这更具体,这是第二种方法的一个小例子。为简洁起见,我没有制作一个“ZoomedImage”类 - 我使用了包含图像的JLabel的JScrollPane,但它完成了这项工作。在右侧是ImageNavigator,它调用“ZoomedImage组件”(实际上是滚动窗口的视口)来获取和设置显示区域的坐标。它绘制一个红色矩形,突出显示该部分。您可以使用滚动条,使用导航器或调整窗口大小来调整显示的区域。这不是太复杂,但希望它包含一些有用的见解:

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

class ImageNavigatorExample {
    public static void main(String[] args) throws Throwable {
        File imageFile = new File( // change file to one you have!
            "Shallow Waters in the South Pacific.jpg");
        BufferedImage image = javax.imageio.ImageIO.read(imageFile);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        JScrollPane imageScroller = new JScrollPane(new JLabel(new ImageIcon(image)));
        imageScroller.setPreferredSize(new Dimension(640, 480));
        frame.add(imageScroller);
        frame.add(new ImageNavigator(image, imageScroller.getViewport()), BorderLayout.EAST);
        frame.pack();
        frame.setVisible(true);
    }


    private static class ImageNavigator extends JPanel {
        private final BufferedImage image;
        private final JViewport viewport;

        public ImageNavigator(BufferedImage image, final JViewport viewport) {
            this.image = image;
            this.viewport = viewport;
            viewport.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    repaint();
                }
            });
            MouseAdapter mouseAdapter = new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    int xImage = Math.round(e.getX() / scale());
                    int yImage = Math.round(e.getY() / scale());

                    viewport.setViewPosition(new Point(
                        Math.max(0, xImage - viewport.getExtentSize().width / 2),
                        Math.max(0, yImage - viewport.getExtentSize().height / 2)));
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    mousePressed(e);
                }
            };
            this.addMouseListener(mouseAdapter);
            this.addMouseMotionListener(mouseAdapter);
        }

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

        private float scale() {
            return (float)this.getWidth() / image.getWidth();
        }

        @Override
        public void paintComponent(Graphics g1) {
            super.paintComponent(g1);

            Graphics2D g = (Graphics2D)g1.create();
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g.scale(scale(), scale());
            g.drawImage(image, 0, 0, null);

            g.setColor(Color.red);
            g.setStroke(new BasicStroke(scale()));
            g.draw(viewport.getViewRect());
        }
    }
}

它看起来像什么:

screenshot