Wie kann ich in JPanel zoomen, ohne das Zentrum zu bewegen: Mathe oder Swing?

Ich versuche mit Swing eine zoombare Karte zu erstellen. Die Map ist ein JPanel in einem JScrollPane. Beim Vergrößern ändert sich die Größe der Karte und paint () malt die Elemente an einer anderen Position. Das alles funktioniert super.

Das ScrollPane änderte jedoch nicht das Ansichtsfenster, während die Bildgröße vergrößert wurde, sodass beim Vergrößern immer die Elemente verschoben wurden, die ich vom Bildschirm aus betrachtete. Ich habe versucht, dies mit zu lösenscrollRectToVisible()Aber ich schaffe es nicht, die richtigen Koordinaten für das Rechteck zu finden, entweder weil ich die Geometrie nicht beherrsche oder weil ich Swing nicht so gut verstehe.

Folgendes habe ich:

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 meiner Meinung nach nicht sehr überraschend ist):

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 etwas schief läuft? Es scheint mir, dass ich eine gültige Berechnung des aktuellen Mittelpunkts der Karte durchgeführt habe, und mit einem festen Zoompunkt funktioniert es ...

Bearbeiten: Daher ist es hier schwierig, das neue Ansichtsfenster-Rechteck basierend auf dem alten Ansichtsfenster-Rechteck zu erstellen.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage