Ich versuche eine zoombare Karte mit Swing zu machen. Die Map ist ein JPanel in einem JScrollPane. Wenn gezoomt wird, ändert die Karte die Größe und paint() zeichnet die Elemente an einer anderen Position. Das alles funktioniert großartig.Wie zoomen Sie in JPanel hinein, ohne das Zentrum zu verschieben: Mathe oder Swing?
Das ScrollPane änderte jedoch nicht das Ansichtsfenster, während die Bildgröße erhöht wurde, so dass das Einzoomen die Elemente, die ich betrachtete, immer aus dem Bildschirm herausbewegte. Ich habe versucht, dies mit scrollRectToVisible()
zu lösen, aber ich bekomme nicht die richtigen Koordinaten für das Rechteck, entweder weil ich die Geometrie nicht schaffe oder weil ich Swing nicht so gut verstehe.
Hier ist, was ich habe:
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);
}
}
Und hier ist die Scaler-Klasse (die nichts anderes tut sehr überraschend, glaube ich):
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));
}
}
Wer kann mir sagen, wo die Dinge schief gehen? Es scheint mir, dass ich eine gültige Berechnung der aktuellen Mitte der Karte hat, und mit einem Zoom-Punkt fixiert es funktioniert ...
Edit: so die harte Sache hier ist die neue Ansichtsfenster Rechteck basierend zu erstellen auf dem alten Ansichtsfensterrechteck.
railMap? Du würdest nicht an etwas wie JMRI arbeiten, oder? ;-) – geowar