我正在尝试使用 Swing 制作可缩放的地图。该地图是 JScrollPane 中的 JPanel。放大时,地图会改变大小,而paint() 会将元素绘制在不同的位置。这一切都很好。
但是,ScrollPane 在增加图像大小时并没有改变视口,因此放大总是将我正在查看的元素移出屏幕。我试图用 解决这个问题scrollRectToVisible()
,但我无法为矩形获得正确的坐标,要么是因为我在做几何图形时失败,要么是因为我不太了解 Swing。
这是我所拥有的:
public class MapPanel extends JPanel {
[...]
public void setZoom(double zoom) {
// get the current viewport rectangle and its center in the scaled coordinate system
JViewport vp = (JViewport) this.getParent();
Rectangle rect = vp.getViewRect();
Point middle = getMiddle(rect);
Dimension dim = rect.getSize();
// zoom in
scaler.setZoom(zoom);
setPreferredSize(scaler.transform(dim));
this.revalidate();
// calculate the full size of the scaled coordinate system
Dimension fullDim = scaler.transform(dim);
// calculate the non-scaled center of the viewport
Point nMiddle = new Point((int) ((double) (middle.x)/fullDim.width*dim.width),(int) ((double) (middle.y)/fullDim.height*dim.height));
// this should do the trick, but is always a bit off towards the origin
scrollRectToVisible(getRectangleAroundPoint(nMiddle));
// the below alternative always zooms in perfectly to the center of the map
// scrollRectToVisible(getRectangleAroundPoint(new Point(400,300)));
}
private Rectangle getRectangleAroundPoint(Point p){
Point newP = scaler.transform(p);
Dimension d = railMap.getDimension();
Point corner = new Point(newP.x-d.width/2,newP.y-d.height/2);
return new Rectangle(corner,d);
}
private Point getMiddle(Rectangle r){
return new Point(r.x+r.width/2,r.y+r.height/2);
}
}
这是 Scaler 类(我认为它没有什么令人惊讶的):
public class Scaler {
private double zoom = 1;
public void setZoom(double zoom) {
this.zoom = zoom;
}
public Point transform(Point2D p){
return new Point((int) (p.getX()*zoom), (int) (p.getY()*zoom));
}
public Dimension transform(Dimension d){
return new Dimension((int) (d.width*zoom), (int) (d.height*zoom));
}
}
谁能告诉我哪里出了问题?在我看来,我对地图的当前中心进行了有效计算,并且使用固定的缩放点它确实可以工作......
编辑:所以这里的难点是根据旧的视口矩形创建新的视口矩形。