Sto cercando di creare una mappa zoomabile con Swing. La mappa è un JPanel in un JScrollPane. Quando ingrandito, la mappa cambia dimensione e paint() dipinge gli elementi in una posizione diversa. Tutto funziona alla grande.Come ingrandire JPanel senza spostare il centro: matematica o swing?
Tuttavia, ScrollPane non ha modificato la vista aumentando le dimensioni dell'immagine, pertanto lo zoom in avanti ha spostato sempre gli elementi che stavo osservando dallo schermo. Ho provato a risolverlo con scrollRectToVisible()
, ma non riesco a ottenere le coordinate giuste per il rettangolo, perché non riesco a fare la geometria o perché non capisco perfettamente Swing.
Ecco quello che ho:
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);
}
}
Ed ecco la classe Scaler (che non fa nulla sorprendente, credo):
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));
}
}
Chi può dirmi dove le cose stanno andando male? Mi sembra che abbia fatto un calcolo valido del centro corrente della mappa e con un punto di zoom fisso funziona ...
Modifica: quindi la cosa difficile qui è creare il nuovo rettangolo di visualizzazione basato sul vecchio rettangolo di visualizzazione.
railMap? Non lavoreresti su qualcosa come JMRI, vero? ;-) – geowar