Pregunta

El código que tengo aquí es utilizar un MouseAdapter para escuchar al usuario a "dibujar" un cuadro alrededor del área de una imagen que les gustaría para acercar y calcular la relación de la caja de la imagen. A continuación, cambia el tamaño de la imagen a la relación calculada. Esta parte funciona.

El problema que estoy teniendo es hacer la vista JScrollPane aparecen como si todavía está en la misma posición superior izquierda después de que la imagen ha sido redimensionada. He intentado varios métodos que parecen haber conseguido cerca del resultado que quiero pero no exactamente.

Este es el oyente que se encuentra la relación de escala y establece la posición:

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.Graphics;
import java.awt.Point;

import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.JComponent;

public class DynamicZoom extends MouseAdapter {

private Point start;
private Point end;
private double zoom = 1.0;
private JScrollPane pane;
private JViewport port;


public void mousePressed(MouseEvent e) {
    if(e.getButton() == MouseEvent.BUTTON1) {
        this.pane = (JScrollPane)e.getSource();
        this.port = pane.getViewport();
        start = e.getPoint();
    }
}

public void mouseReleased(MouseEvent e) {
    if(this.pane != null) {
        Point curr = this.port.getViewPosition();
        end = e.getPoint();

        ImageComponent canvas = (ImageComponent)this.port.getView();
        zoom = canvas.getScale();
        double factor = 0.0;
        double selectedWidth = Math.abs(end.getX() - start.getX());
        double selectedHeight = Math.abs(end.getY() - start.getY());
        if(selectedWidth > selectedHeight)
            factor = this.port.getWidth() / selectedWidth;
        else
            factor = this.port.getHeight() / selectedHeight;

        zoom *= factor;
        int x = (int)((start.x+curr.x)*zoom);
        int y = (int)((start.y+curr.y)*zoom);

        Point point = new Point(x, y);

        ((ImageComponent)(this.port.getView())).setScale(zoom);

        ResizeViewport.resize(pane);
        this.port.setViewPosition(point);
    }
}

public void mouseDragged(MouseEvent e) {
    if(this.pane != null) {
        Graphics g = this.port.getGraphics();
        int width = this.start.x - e.getX();
        int height = this.start.y - e.getY();

        int w = Math.abs( width );
        int h = Math.abs( height );
        int x = width < 0 ? this.start.x : e.getX();
        int y = height < 0 ? this.start.y : e.getY();
        g.drawRect(x, y, w, h);
        this.port.repaint();
    }
}

}

Este es el ImageComponent que cambia el tamaño y muestra la imagen:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.JComponent;

public class ImageComponent extends JComponent {
private static final long serialVersionUID = 1975488835382044371L;
private BufferedImage img = null;

private double scale = 0.0;

public ImageComponent() {}

public ImageComponent(BufferedImage img) {
    this.displayPage(img);
}

@Override
public void paint(Graphics g) {
    Graphics2D g2 = ((Graphics2D)g);
    if(this.img != null) {
        int width = (int)(this.img.getWidth() * this.scale);
        int height = (int)(this.img.getHeight() * this.scale);
        this.setPreferredSize(new Dimension(width, height));
        g2.drawImage(this.img, 0, 0, width, height, null, null);
        g2.dispose();
    }
}

public void displayPage(BufferedImage pic) {
    if(img != null) {
        this.img = pic;
    }
}

public BufferedImage getPage() {
    return this.img;
}

public void setScale(double ratio) {
    if(ratio > .04) {
        this.scale = ratio;
        this.repaint();
    }
}

public double getScale() {
    return this.scale;
}
}

El ResizeViewport obliga a la ventana para mostrar toda la ImageComponent cuando se amplía porque de lo contrario se recortará la imagen en el tamaño que era anteriormente:

import java.awt.Dimension;

import javax.swing.JScrollPane;
public class ResizeViewport {
public static void resize(JScrollPane scroll) {
    int vw = scroll.getWidth()-scroll.getVerticalScrollBar().getWidth();
    int vh = scroll.getHeight()-scroll.getHorizontalScrollBar().getHeight();
    scroll.getViewport().setViewSize(new Dimension(vw, vh));
}
}
¿Fue útil?

Solución

Resulta que no hay nada malo con las matemáticas utilizadas para calcular la posición o la forma en que he diseñado el código. El problema era que el ImageComponent seguía pintando en otro hilo cuando se está calculando la posición; por lo tanto, la devolución de valores "falsos" para la () métodos getWidth () y getHeight. He resuelto el problema usando el siguiente código:

EventQueue.invokeLater(new Runnable() {
   public void run() {
      port.setViewPosition(new Point(x,y));
   }
});

Esto permite que la pintura para terminar antes de tratar de calcular el tamaño de la imagen y ajuste de la posición en el JScrollPane. Problema resuelto. Todavía me gustaría lanzar un agradecimiento a las personas que se tomaron el tiempo para revisar al menos este problema.

Otros consejos

Yo tenía un problema similar, pero a veces el panel pintado dieron mal la primera vez después de cambiar el tamaño, después de horas de tratar de encontrar una solución que encontré una solución!

Después de un cambio de tamaño del panel en el panel de desplazamiento es mejor es destruir ventana mediante el establecimiento en nulo, y luego añadir el panel posterior a scrollpane recreará una nueva ventana gráfica y todo está funcionando!

// Old viewport has to be replaced
scrollPane.setViewport(null);
scrollPane.setViewportView(zoomablePanel);

/ Anders

  

El problema que estoy teniendo es hacer   la vista JScrollPane aparezca como si se   se encuentra aún en la misma posición superior izquierda   después de que la imagen ha sido redimensionada.

Lo sentimos, no estoy seguro de lo que estás pidiendo. Puede ser que sea capaz de dar una respuesta si a clarificar un poco.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top