2012-01-15 23 views
1

私はJScrollPaneの中に(JComponentから継承した)マップを表示するJavaプログラムに取り組んでいます。 MouseWheelListenerが起動すると、マップはズームし、JScrollPaneのビューポートはマウスの位置を中心に調整されます。Java:再描画せずにコンポーネントのサイズを変更しますか?

setSize(Dimension d)を呼び出すと、ビューが調整される直前に地図が再描画され、「スタッター」が発生します。しかし、setSizeの実行が完了するか、またはビューポートを「センタリングする」ための計算が(getHeight()getWidth()コールのために)かわいくなるまでビューを調整することはできません。したがって、ビューポートの調整はinvokeLaterで呼び出された実行可能ファイル内にあります。

私は以前のマップサイズとビューポートの位置から新しいビューに直接移動する方法を見つけたいと思いますが、シーンを2度再ペイントすることはありません。

setIgnoreRepaint(boolean)私のためには機能しませんでした。これについて別の方法がありますか?

編集:私の問題を再現するサンプルコードから、私はどのように作業しましたか?画像をすばやくスクロールすると、六角形のサイズ変更とビューポートの新しい位置への調整の間に少しばかげがあることがわかります。

六角形が2回再描画されているのがわかります。 (のsetSize()メソッドが呼び出されるとときとsetViewPosition()メソッドが呼び出されるととき。)

import java.awt.*; 
import java.awt.event.*; 
import java.awt.image.BufferedImage; 
import javax.swing.*; 

public class ZoomWithSelectionInViewport implements MouseWheelListener{ 

private int zoom = 80; 

JComponent b; 
int hexSize = 3; 

public ZoomWithSelectionInViewport() throws Exception{ 

    b = new JComponent() { 

     private static final long serialVersionUID = 1L; 

     @Override 
     public Dimension getMinimumSize() { 
      return new Dimension(700, 700); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = ((Graphics2D) g); 

      int vertOffsetX, vertOffsetY, horizOffsetX, horizOffsetY; 

      vertOffsetX = (int)((double)hexSize* Math.sqrt(3.0f)); 
      vertOffsetY = (int)((double)-hexSize-1* Math.sqrt(3.0f)/2.0f); 

      horizOffsetX = (int) ((double)hexSize* Math.sqrt(3.0f)); 
      horizOffsetY = (int) ((double)hexSize+1* Math.sqrt(3.0f)/2.0f); 

      for(int x = 0; x < 50; x++) 
      { 
       for(int y = 0; y < 50; y++) 
       { 
        int[] xcoords = new int[6]; int[] ycoords = new int[6]; 
        for(int i = 0; i < 6; i++) 
        { 
         xcoords[i] = (int)((hexSize+x * horizOffsetX + y * vertOffsetX) + (double)hexSize * Math.cos(i * 2 * Math.PI/6)); 
         ycoords[i] = (int)(((getSize().height /2)+ x * horizOffsetY + y * vertOffsetY) + (double)hexSize * Math.sin(i * 2 * Math.PI/6)); 
        } 
        g2d.setStroke(new BasicStroke(hexSize/2.5f)); 
        g2d.setColor(Color.GRAY); 

        g2d.drawPolygon(xcoords, ycoords, 6); 
       } 
      } 

     } 
    }; 
    JScrollPane view = new JScrollPane(b); 

    b.addMouseWheelListener(this); 
    JFrame f = new JFrame(); 
    f.setLocation(10, 10); 
    f.setDefaultCloseOperation(3); 
    f.add(view); 
    f.setSize(500,500); 
    f.setVisible(true); 
    view.setWheelScrollingEnabled(false); 
} 

    public void mouseWheelMoved(MouseWheelEvent e) { 
     zoom = 100*-Integer.signum(e.getWheelRotation()); 
     if(hexSize - Integer.signum(e.getWheelRotation()) > 0) 
      hexSize-= Integer.signum(e.getWheelRotation()); 
     Dimension targetSize = new Dimension(b.getWidth()+zoom,b.getHeight()+zoom); 
     b.setPreferredSize(targetSize); 
     b.setSize(targetSize); 

     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JViewport tempView = (JViewport)b.getParent(); 
       tempView.setViewPosition(new Point(b.getWidth()/2,b.getHeight()/2));    
      } 
     }); 

    } 


public static void main(String[] args) { 
    EventQueue.invokeLater(new Runnable() { 

     @Override 
     public void run() { 
      try { 
       ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 
} 
+0

私の質問http://stackoverflow.com/questions/8880111/resize-graphics2d-into-jscrollpaneを参照してください。 – mKorbel

答えて

4

私の好奇心、happends何ノーアイデア、あなたはこのSSCCEがあなたの問題を追加して編集してご使用ください可能性がありコードあなたの質問

enter image description hereenter image description hereenter image description hereenter image description here

import java.awt.*; 
import java.awt.event.*; 
import java.awt.image.BufferedImage; 
import javax.swing.*; 

public class ZoomWithSelectionInViewport { 

    private Point startPoint = new Point(0, 0); 
    private Point rectLocale = new Point(); 
    private Dimension rectSize = new Dimension(); 
    private int zoom = 80; 
    private BufferedImage capture = null; 
    private BufferedImage raw; 

    public ZoomWithSelectionInViewport() throws Exception { 
     raw = new Robot().createScreenCapture(new Rectangle(
       Toolkit.getDefaultToolkit().getScreenSize())); 
     MouseBehavior behavior = new MouseBehavior(); 
     JPanel b = new JPanel() { 

      private static final long serialVersionUID = 1L; 

      @Override 
      public Dimension getMinimumSize() { 
       return new Dimension(500, 500); 
      } 

      @Override 
      public Dimension getPreferredSize() { 
       return new Dimension(500, 500); 
      } 

      @Override 
      protected void paintComponent(Graphics g) { 
       super.paintComponent(g); 
       Graphics2D g2d = ((Graphics2D) g); 
       g2d.drawImage(raw, 0, 0, null); 
       if (capture != null) { 
        int width2 = (int) (rectSize.width + rectSize.width * (zoom/500d)); 
        int height2 = (int) (rectSize.height + rectSize.height * (zoom/500d)); 
        int x2 = rectLocale.x - ((width2 - rectSize.width)/2); 
        int y2 = rectLocale.y - ((height2 - rectSize.height)/2); 
        Image scaledInstance = capture.getScaledInstance(
          width2, height2, Image.SCALE_AREA_AVERAGING); 
        g2d.drawImage(scaledInstance, x2, y2, null); 
        g2d.drawRect(x2, y2, width2, height2); 
       } else { 
        g2d.draw(new Rectangle(rectLocale, rectSize)); 
       } 
      } 
     }; 
     b.addMouseMotionListener(behavior); 
     b.addMouseListener(behavior); 
     b.addMouseWheelListener(behavior); 
     JFrame f = new JFrame(); 
     f.setLocation(10, 10); 
     f.setDefaultCloseOperation(3); 
     f.add(b); 
     f.pack(); 
     f.setVisible(true); 
    } 

    private class MouseBehavior extends MouseAdapter { 

     @Override 
     public void mousePressed(MouseEvent e) { 
      startPoint = e.getPoint(); 
      rectLocale = new Point(); 
      rectSize = new Dimension(); 
      capture = null; 
      if (e.getSource() instanceof JComponent) { 
       ((JComponent) e.getSource()).repaint(); 
      } 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
      Point currentPoint = e.getPoint(); 
      rectSize.width = Math.abs(currentPoint.x - startPoint.x); 
      rectSize.height = Math.abs(currentPoint.y - startPoint.y); 
      if (e.isShiftDown()) { 
       rectSize.width = rectSize.height = Math.min(rectSize.width, rectSize.height); 
       int dx = startPoint.x - rectSize.width; 
       int dy = startPoint.y - rectSize.height; 
       rectLocale.x = startPoint.x < currentPoint.x ? startPoint.x : Math.max(dx, dy); 
       rectLocale.y = startPoint.y < currentPoint.y ? startPoint.y : Math.min(dx, dy); 
      } else { 
       rectLocale.x = Math.min(currentPoint.x, startPoint.x); 
       rectLocale.y = Math.min(currentPoint.y, startPoint.y); 
      } 
      if (e.getSource() instanceof JComponent) { 
       ((JComponent) e.getSource()).repaint(); 
      } 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      if (rectSize.width <= 0 || rectSize.height <= 0) { 
       capture = null; 
      } else { 
       capture = raw.getSubimage(Math.max(0, rectLocale.x), 
         Math.max(0, rectLocale.y), rectSize.width, rectSize.height); 
      } 
      if (e.getSource() instanceof JComponent) { 
       ((JComponent) e.getSource()).repaint(); 
      } 
     } 

     @Override 
     public void mouseWheelMoved(MouseWheelEvent e) { 
      zoom = Math.min(2000, Math.max(0, zoom + e.getUnitsToScroll() * 10)); 
      if (e.getSource() instanceof JComponent) { 
       ((JComponent) e.getSource()).repaint(); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        ZoomWithSelectionInViewport example = new ZoomWithSelectionInViewport(); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 
} 

は、代替は可能性があり

import java.awt.event.*; 
import java.awt.*; 
import javax.swing.*; 
import java.awt.geom.*; 

public class ZoomDemo { 

    private PaintSurface canvas = new PaintSurface(); 
    private JFrame frame = new JFrame(); 
    private AffineTransform aT = new AffineTransform(); 
    private Point2D p1 = null; 
    private Point2D p2 = null; 

    public ZoomDemo() { 
     frame.setSize(500, 500); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setLocationRelativeTo(null); 
     ScaleListener scaleListener = new ScaleListener(); 
     canvas.addMouseWheelListener(scaleListener); 
     canvas.addMouseListener(scaleListener);  
     frame.add(canvas); 
     frame.setVisible(true); 
    } 

    public class ScaleListener extends MouseAdapter { 

     private double scale = 1; 

     @Override 
     public void mouseClicked(MouseEvent e) { 
      p1 = e.getPoint(); 
      try { 
       p2 = aT.inverseTransform(p1, new Point2D.Double()); 
       /* 
       * p1 is the point relative to canvas where the user physically 
       * held the mouse. 
       * 
       * Since you may want to deal with a virtual mouse location 
       * relative to an untransformed canvas, you inverse transform p1 
       * to p2. 
       * 
       * For example: when the user held the mouse over, let's say, 
       * the displayed left upper corner of the red rectangle. 
       * 
       * p2 now will point to the upper left corner of the red 
       * rectangle in an untransformed canvas. 
       */ 
       applyScale(); 
      } catch (NoninvertibleTransformException e1) { 
       e1.printStackTrace(); 
      } 
      canvas.repaint(); 
     } 

     @Override 
     public void mouseWheelMoved(MouseWheelEvent e) { 
      if (p1 != null && p2 != null) { 
       scale -= (0.05 * e.getWheelRotation()); 
       if (scale > 5) { 
        scale = 5; 
       } 
       if (scale < 1) { 
        scale = 1; 
        aT.setToIdentity(); 
       } else { 
        applyScale(); 
       } 
       canvas.repaint(); 
      } 
     } 

     private void applyScale() { 
      aT.setToIdentity(); 
      // *** variation one (your implementation) 
      aT.translate(p1.getX(), p1.getY()); 
      aT.scale(scale, scale); 
      aT.translate(-p2.getX(), -p2.getY()); 
      // *** variation two 
      // aT.translate(p1.getX(), p1.getY()); 
      // aT.scale(scale, scale); 
      // aT.translate(-p1.getX(), -p1.getY()); 
      // *** variation three 
      // aT.translate(p2.getX(), p2.getY()); 
      // aT.scale(scale, scale); 
      // aT.translate(-p2.getX(), -p2.getY()); 
     } 
    } 

    public class PaintSurface extends JComponent { 

     private static final long serialVersionUID = 1L; 

     { 
      this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); 
     } 

     /* 
     * Override paintComponent, not paint!!! 
     */ 
     @Override 
     protected void paintComponent(Graphics g) { 
      Graphics2D g2 = (Graphics2D) g.create(); 
      try { 
       g2.setColor(Color.black); 
       g2.fillRect(0, 0, getWidth(), getHeight()); 
       // g2.setTransform(aT); <<<<<<<<< !!!!!!! 
     /* 
       * A transform (translation for example) may already have been 
       * applied to the Graphics object by a parent. This is removed 
       * by setTransform. 
       */ 
       g2.transform(aT); // <<<<<<<<<< !!!!!!! 
       g2.setColor(Color.red); 
       g2.drawRect(50, 50, 100, 100); 
       g2.setColor(Color.blue); 
       g2.drawRect(200, 200, 150, 50); 
       if (p2 != null) { 
        g2.setColor(Color.green); 
        g2.fill(new Rectangle2D.Double(p2.getX() - 4, p2.getY() - 4, 8, 8)); 
       } 
      } finally { 
       g2.dispose(); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       ZoomDemo zoomDemo = new ZoomDemo(); 
      } 
     }); 
    } 
} 

同じ質問、

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.RenderingHints; 
import java.awt.event.MouseWheelEvent; 
import java.awt.event.MouseWheelListener; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JViewport; 

//http://stackoverflow.com/questions/6819243/jscrollpane-jumping-when-scrollbars-start-being-used 

public class LockViewPortToPoint extends JFrame { 

    private static final long serialVersionUID = 1L; 

    public static void main(String[] arg) { 
     LockViewPortToPoint lockViewPortToPoint = new LockViewPortToPoint(); 
    } 

    public LockViewPortToPoint() { 
     initComponents(); 
     setVisible(true); 
    } 

    private void initComponents() { 
     setLayout(new BorderLayout()); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setSize(600, 600); 
     setPreferredSize(new Dimension(600, 600)); 
     add(new TopPanel()); 
    } 

    private class TopPanel extends JPanel { 

     private static final long serialVersionUID = 1L; 
     private JScrollPane scrollPane; 

     TopPanel() { 
      setPreferredSize(new Dimension(500, 500)); 
      scrollPane = new JScrollPane(new InteriorPanel()); 
      scrollPane.setPreferredSize(new Dimension(500, 500)); 
      scrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(10, 490)); 
      scrollPane.getHorizontalScrollBar().setPreferredSize(new Dimension(490, 10)); 
      scrollPane.setWheelScrollingEnabled(false); 
      scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 
      scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 
      add(scrollPane); 
     } 
    } 

    private class InteriorPanel extends JPanel { 

     private static final long serialVersionUID = 1L; 
     private double scale = 10.0; 
     private final double scaleModifier = 0.1; 
     private final int width = 10; 
     private Point loc = new Point(0, 0); 
     private final int SIZE = 10; 
     private Point orig = new Point(250, 250); 

     InteriorPanel() { 
      super(true); 
      setPreferredSize(new Dimension((int) (scale * width * SIZE), (int) (scale * width * SIZE))); 
      this.addMouseWheelListener(new MapMouseWheelListener()); 
     } 

     @Override 
     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2D = (Graphics2D) g; 
      g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
      g2D.scale(scale, scale); 
      for (int row = 0; row <= SIZE; row++) { 
       for (int col = 0; col < SIZE; col++) { 
        if ((col + row) % 2 == 0) { 
         g2D.setColor(Color.white); 
        } else { 
         g2D.setColor(Color.black); 
        } 
        g2D.fillRect(col * width, row * width, width, width); 
       } 
      } 
     } 

     private void incrementScale(int notches) { 
      double modifier = 0; 
      final double prevScale = scale; 
      if (notches != 0) { 
       modifier = 1.0 + -notches/Math.abs(notches) * scaleModifier; 
      } 
      scale *= Math.pow(modifier, Math.abs(notches)); 
      /*if (scale * width < 1) { 
      scale = 1.0/width; 
      } else if (scale * width * 3 > parentHeight || scale * width * 3 > parentWidth) { 
      if (parentHeight > parentWidth) { 
      scale = parentWidth/3.0/width; 
      } else { 
      scale = parentHeight/3.0/width; 
      } 
      } else if (scale * width * SIZE < parentWidth) { 
      scale = parentWidth/(double)SIZE/width; 
      } else if (scale * width * SIZE < parentHeight) { 
      scale = parentHeight/(double)SIZE/width; 
      }*/ 
      setPreferredSize(new Dimension((int) (scale * width * SIZE), (int) (scale * width * SIZE))); 
      orig = new Point(((int) (scale * width * SIZE))/2, ((int) (scale * width * SIZE)/2)); 
      final JViewport viewport = ((JViewport) (getParent().getParent().getComponent(0))); 
      javax.swing.SwingUtilities.invokeLater(new Runnable() { 

       public void run() { 
        viewport.setViewPosition(new Point(
          orig.x - (int) Math.round(loc.x * (1 - scale/prevScale)), 
          orig.y - (int) Math.round(loc.y * (1 - scale/prevScale)))); 
       } 
      }); 
      /*viewport.scrollRectToVisible(new Rectangle(new Point(
      orig.x - (int) Math.round(loc.x * (1 - scale/prevScale)), 
      orig.y - (int) Math.round(loc.y * (1 - scale/prevScale))))); */ 
      System.out.println(orig + "\n " + loc + "\n " + (1 - scale/prevScale)); 
      revalidate(); 
      repaint(); 
     } 

     private class MapMouseWheelListener implements MouseWheelListener { 

      @Override 
      public void mouseWheelMoved(MouseWheelEvent e) { 
       loc = e.getPoint(); 
       incrementScale(e.getWheelRotation()); 
      } 
     } 
    } 
} 

別の例

import java.awt.*; 
import java.awt.event.*; 
import java.awt.geom.*; 
import javax.swing.*; 

//http://stackoverflow.com/questions/115103/how-do-you-implement-position-sensitive-zooming-inside-a-jscrollpane 
public class FPanel extends javax.swing.JPanel { 

    private static final long serialVersionUID = 1L; 
    private Dimension preferredSize = new Dimension(400, 400); 
    private Rectangle2D[] rects = new Rectangle2D[50]; 

    public static void main(String[] args) { 
     JFrame jf = new JFrame("test"); 
     jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     jf.setSize(400, 400); 
     jf.add(new JScrollPane(new FPanel())); 
     jf.setVisible(true); 
    } 

    public FPanel() { 
     // generate rectangles with pseudo-random coords 
     for (int i = 0; i < rects.length; i++) { 
      rects[i] = new Rectangle2D.Double(
        Math.random() * .8, Math.random() * .8, 
        Math.random() * .2, Math.random() * .2); 
     } 
     // mouse listener to detect scrollwheel events 
     addMouseWheelListener(new MouseWheelListener() { 

      @Override 
      public void mouseWheelMoved(MouseWheelEvent e) { 
       updatePreferredSize(e.getWheelRotation(), e.getPoint()); 
      } 
     }); 
    } 

    private void updatePreferredSize(int wheelRotation, Point stablePoint) { 
     double scaleFactor = findScaleFactor(wheelRotation); 
     scaleBy(scaleFactor); 
     Point offset = findOffset(stablePoint, scaleFactor); 
     offsetBy(offset); 
     getParent().doLayout(); 
     revalidate(); 
     repaint(); 
    } 

    private double findScaleFactor(int wheelRotation) { 
     double d = wheelRotation * 1.08; 
     return (d > 0) ? 1/d : -d; 
    } 

    private void scaleBy(double scaleFactor) { 
     int w = (int) (getWidth() * scaleFactor); 
     int h = (int) (getHeight() * scaleFactor); 
     preferredSize.setSize(w, h); 
    } 

    private Point findOffset(Point stablePoint, double scaleFactor) { 
     int x = (int) (stablePoint.x * scaleFactor) - stablePoint.x; 
     int y = (int) (stablePoint.y * scaleFactor) - stablePoint.y; 
     return new Point(x, y); 
    } 

    private void offsetBy(Point offset) { 
     Point location = getLocation(); 
     setLocation(location.x - offset.x, location.y - offset.y); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return preferredSize; 
    } 
    private Rectangle2D r = new Rectangle2D.Float(); 

    @Override 
    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     g.setColor(Color.red); 
     int w = getWidth(); 
     int h = getHeight(); 
     for (Rectangle2D rect : rects) { 
      r.setRect(rect.getX() * w, rect.getY() * h, 
        rect.getWidth() * w, rect.getHeight() * h); 
      ((Graphics2D) g).draw(r); 
     } 
    } 
} 
+0

右1なし)Maps、2)JViewportを中心にする、3)「stutter」を引き起こすあなたのコメントが削除されました、なぜ??? ???、btwこれは非常に良い質問です、面白いsoooooo、ちょうどあなたはあなたのコメントを削除しました。あなたのコードを投稿して私たちを助けなければならない – mKorbel

+0

申し訳ありません!あなたのコードサンプルから私の問題を再現しようと努めている間、私は自分のコメントを削除しました。私はそれに取り組んでいます! –

+0

すべての権利は、私のサンプルコードから一緒に石けんの例を使用して問題を示すために私の質問を編集しました。ありがとう、mKorbel! –

関連する問題