2

ここにあるコードは、MouseAdapter を使用して、ユーザーがズームインしたい画像の領域の周りにボックスを「描画」し、ボックスと画像の比率を計算することをリッスンします。次に、計算された比率に合わせて画像のサイズを変更します。この部分は機能します。

私が抱えている問題は、画像のサイズが変更された後、JScrollPane ビューが同じ左上の位置にあるかのように表示されることです。私が望む結果に近づいたように見えるいくつかの方法を試しましたが、正確ではありません。

これは、スケール比を見つけて位置を設定するリスナーです。

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();
    }
}

}

これは、サイズを変更して画像を表示する ImageComponent です。

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;
}
}

ResizeViewport は、ビューポートが拡大されたときに ImageComponent 全体を表示するように強制します。そうしないと、以前のサイズで画像がクリップされるためです。

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));
}
}
4

2 に答える 2

5

位置の計算に使用した計算やコードの設計方法に問題がないことがわかりました。問題は、位置が計算されているときに ImageComponent がまだ別の Thread で描画されていたことです。したがって、getWidth() および getHeight() メソッドに対して「false」値を返します。次のコードを使用して問題を解決しました。

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

これにより、画像のサイズを計算して JScrollPane で位置を設定する前に、ペイントを終了できます。問題が解決しました。少なくともこの問題をレビューするために時間を割いてくれた人々に感謝したいと思います.

于 2010-02-04T18:17:04.393 に答える
2

私は同様の問題を抱えていましたが、サイズ変更後に初めてパネルが間違ってペイントされることがあり、何時間も回避策を見つけようとした後、解決策を見つけました!

スクロールペインでパネルのサイズを変更した後は、null に設定してビューポートを破棄し、パネルをスクロールペインに追加して新しいビューポートを再作成し、すべてが機能するようにすることをお勧めします。

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

/アンダース

于 2014-07-28T10:51:58.677 に答える