Zoom zur Mouseposition in ScrollPane

daMSTRin

Neues Mitglied
Hi,
Ich versuche gerade eine Zoom Funktion für ein ScrollPane zu implementieren.
Dabei will ich sicherstellen, dass der Punkt unter der Mouse nach dem Skalieren auch
unter der Mouse bleibt.
Meine Überlegung:
s.x,s.y seien die Koordinaten des Viewport
m.x,m.y seien die Koordinaten der Mouse Relativ zum ScrollPane

Dann ist der Punkt, dessen Position gleich bleiben soll, gegeben durch (s.x+m.x),(s.y+m.y).
Wenn ich also um den Faktor 10% Zoome, bekommt dieser Punkt die Koordinaten (s.x+m.x)*0.9,(s.y+m.y)*0.9 bzw. (s.x+m.x)*1.1,(s.y+m.y)*1.1.
Damit dieser Punkt unter der Mouse bleibt muss der Viewport also doch auf
(s.x+m.x)*0.9-m.x,(s.y+m.y)*0.9-m.y setzten oder?

Anbei die Methode die dies Implementieren sollte.
Java:
    private void jScrollPaneMouseWheelMoved(MouseWheelEvent evt) {                                             
        viewPosition = jScrollPane.getViewport().getViewPosition();
        Point mousepos=jScrollPane.getMousePosition(true);
        scale = scale + evt.getWheelRotation() * 0.10f;
        if (1 > scale && scale > 0.20f) {
            if (evt.getWheelRotation() > 0) {
                jScrollPane.getViewport().setViewPosition(new Point((int) ((viewPosition.x+mousepos.x) * 0.90f)-mousepos.x, (int) (((viewPosition.y+mousepos.y) * 0.90f))-mousepos.y));
            } else if (evt.getWheelRotation() < 0) {
                jScrollPane.getViewport().setViewPosition(new Point((int) (((viewPosition.x+mousepos.x) * 1.10f))-mousepos.x, (int) ((viewPosition.y+mousepos.y) * 1.10f)-mousepos.y));
            }
        } else if (scale <= 0.20f) {
            scale = 0.15f;
        } else if (scale >= 1.0f) {
            scale = 1.0f;
        }
        bild.setScale(scale);
        bild.repaint();


    }

Das Verhalten das ich auf diese Art erreiche ist leider nicht die erwartete :/.
Ich hoffe ihr könnt mir weiterhelfen und meinen Fehler erklären und einen lösungsvorschlag geben.

Danke

mfg daMSTRin
 
Ja, irgendwie stolper' ich da auch jedes mal drüber (obwohl es an sich trivial sein sollte 😳 ). Was ist denn "bild"? Ein KSKB wäre gut.
 
Ein Problem könnte sein, dass du für die Verschiebung der Maus immer von einem Zoomschritt (0.1) ausgehst während sich der tatsächliche Zoom je nach Anzahl der Umdrehungen ändert.
 
Danke für die Antworten, anbei die gesamte Klasse.
An sich ist das bild einfach nur ein Bild das dann entsprechend
beim zeichnen skaliert wird. Ich hab jetzt soweit glaub ich alles
nicht relevante gelöscht.
Bitte entschuldigt wie ich Programmiere, aber im moment Programmiere ich das
Projekt nur so alleine vor mir her. MapBild tut im original mehr als nur das Bild
zeichnen.

danke, mfg daMSTRin
Java:
public class MapPanel extends JPanel {
    private JScrollPane jScrollPane;
    private MapBild bild;
    private Point viewPosition;
    private float scale = 1.0f;

    public MapPanel() {

        String separator = System.getProperty("file.separator");
        String rootPath = System.getProperty("user.dir");
        String imgPath = rootPath + separator + "src" + separator + "hakatastosuniverse" + separator + "images" + separator + "MAP.jpg";

        File file = new File(imgPath);
        BufferedImage a = null;
        try {
            a = ImageIO.read(file);
        } catch (IOException ex) {
            Logger.getLogger(MapPanel.class.getName()).log(Level.SEVERE, null, ex);
        }

        bild = new MapBild(a);
        initComponents();



    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane = new JScrollPane(bild);

        setMinimumSize(new java.awt.Dimension(774, 683));
        setPreferredSize(new java.awt.Dimension(774, 683));

        jScrollPane.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jScrollPane.setPreferredSize(new java.awt.Dimension(1019, 740));
        jScrollPane.setWheelScrollingEnabled(false);
        jScrollPane.addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                jScrollPaneMouseWheelMoved(evt);
            }
        });
        jScrollPane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                jScrollPaneMouseDragged(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 774, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 683, Short.MAX_VALUE)
        );
    }// </editor-fold>                        

    private void jScrollPaneMouseDragged(java.awt.event.MouseEvent evt) {                                         
//ToDo
    }                                        
    
    private void jScrollPaneMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {                                            
        viewPosition = jScrollPane.getViewport().getViewPosition();
        Point mousepos=jScrollPane.getMousePosition(true);
        scale = scale + evt.getWheelRotation() * 0.10f;
        if (1 > scale && scale > 0.20f) {
            if (evt.getWheelRotation() > 0) {
                jScrollPane.getViewport().setViewPosition(new Point((int) ((viewPosition.x+mousepos.x) * 0.90f)-mousepos.x, (int) (((viewPosition.y+mousepos.y) * 0.90f))-mousepos.y));
            } else if (evt.getWheelRotation() < 0) {
                jScrollPane.getViewport().setViewPosition(new Point((int) (((viewPosition.x+mousepos.x) * 1.10f))-mousepos.x, (int) ((viewPosition.y+mousepos.y) * 1.10f)-mousepos.y));
            }
        } else if (scale <= 0.20f) {
            scale = 0.15f;
        } else if (scale >= 1.0f) {
            scale = 1.0f;
        }
        bild.setScale(scale);
        bild.repaint();


    }                                           

    public class MapBild extends JComponent {

        private Image img;
        private float scale = 1.0f;

        public MapBild(){

        }
        public MapBild(Image img) {
            this.img = img;
            int w = img.getWidth(this);
            int h = img.getHeight(this);

            setPreferredSize(new Dimension(w, h));
        }

        public void setScale(float scalep) {
            this.scale = scalep;
        }

        public float getScale() {
            return scale;
        }

        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                    RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2.scale(scale, scale);
            int w = (int) (img.getWidth(bild) * scale);
            int h = (int) (img.getHeight(bild) * scale);
            //g2.drawImage(img, 0, 0,(int)(img.getWidth(bild)*scale),(int)(img.getHeight(bild)*scale), null);
            g2.drawImage(img, 0, 0, null);
            //System.out.println(w+":"+h); 774:683
            setPreferredSize(new Dimension(w, h));
            revalidate();
        }
    } 

}
 
Sitze hier tatsächlich gerade an einem PC ohne Mausrad 😳 aber .. muss bei einer Änderung von 'scale' nicht auch die PreferredSize des Bild-Panels angepasst werden? Ansonsten müßte man das halt mal zu einem KSKB machen...
 

Zurück
Oben