我正在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,所以我无法获取正确的部分。如何在图像大小后立即更新图像?
答案 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());
}
}
}
它看起来像什么: