2

Java6/7を使用して再利用可能なJPanel画像ビューアを作成しようとしています。サイズ変更中にJPanel(ビューポートの原点)の左上隅が移動しない限り、mouseDraggedを使用して画像ドラッグを実装したり、JPanelのサイズを変更して画像をトリミングまたは表示したりするのに問題はありません。パネルに合わせて画像のサイズを変更したくないことに注意してください。パネルのサイズを変更してトリミングしている間、画像を画面に固定したままにしておきたい。

フレームの左端をドラッグしてビューポートの原点を移動すると、サイズ変更中に画像の原点を動的に再計算しても、サイズ変更操作中にかなりの画像ジッターが発生します。これは、paintComponent()が呼び出されてから、drawImage()の呼び出しによって画像が実際にレンダリングされるまでの間に、ビューポートの原点が変更されたことが原因のようです。上記のジッターを排除する方法について何か考えはありますか?前もって感謝します。

以下の2つのクラスは、動作を示す必要があります。

/***** ImageViewer.java *****/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;

import javax.imageio.ImageIO;

public class ImageViewer extends JFrame
{
    private ImagePanel      canvas;
    private BufferedImage   theImage;
    private JFileChooser    theChooser;

    public ImageViewer( BufferedImage bi )
    {
    canvas= new ImagePanel( );
    add( canvas, BorderLayout.CENTER );

    JPanel control= new JPanel();
    JButton loadBtn= new JButton( "Load Image" );
    control.add( loadBtn );
    add( control, BorderLayout.NORTH );
    loadBtn.addActionListener( new ActionListener() {
        public void actionPerformed( ActionEvent e )
        { doLoad(); }
    });

    theChooser= new JFileChooser();
    }

    public void doLoad()
    {
    File iFile = null;

    int retVal = theChooser.showOpenDialog(this);
    if (retVal == JFileChooser.APPROVE_OPTION) {
        iFile = theChooser.getSelectedFile();
        try {
        theImage = ImageIO.read(iFile);
        } catch (FileNotFoundException ie) {
        System.err.println("File not found");
        System.exit(1);
        } catch (IOException ie) {
        System.err.println("IOException");
        System.exit(1);
        }
        canvas.setImage( theImage );
        repaint();
    }
    }

    /**
     * @param args
     */
    public static void main(String[] args)
    {
    BufferedImage bImage= null;

    ImageViewer theApp= new ImageViewer( bImage );
    theApp.setDefaultCloseOperation(EXIT_ON_CLOSE);

    theApp.pack();
    theApp.setVisible( true );
    }
}

/***** ImagePanel.java *****/
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
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.image.BufferedImage;
import java.awt.event.*;
import java.awt.geom.*;

import javax.swing.JPanel;

public class ImagePanel extends JPanel
{
    private BufferedImage theImage;
    private Dimension preferredSize;
    private double scaleF = 1.0; // image scaling factor
    private Point2D.Double deltaLoc; // dx, dy in scaled units for image upper
                     // left corner from origin to current loc
                         // inside or outside viewport
    private Point panelLastLoc; // last location of upper left corner of the
                // viewport in screen coordinates
    private int lastX;
    private int lastY;
    private PanelState state = PanelState.IDLE;

    public enum PanelState
    {
    IDLE, RESIZING, PMOVING, IMOVING
    };

    public ImagePanel()
    {
    setBackground(Color.GRAY);
    preferredSize = new Dimension(400, 400);

    addHierarchyListener(new HierarchyListener() {
        public void hierarchyChanged(HierarchyEvent he)
        {
        doComponentChanged(he);
        }

    });

    addHierarchyBoundsListener(new HierarchyBoundsAdapter() {
        public void ancestorMoved(HierarchyEvent he)
        {
        doComponentMoved();
        }

        public void ancestorResized(HierarchyEvent he)
        {
        doAncestorResizing();
        }
    });

    addComponentListener(new ComponentAdapter() {
        public void componentResized(ComponentEvent ce)
        {
        doComponentResized();
        }
    });

    addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent me)
        {
        setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        state = PanelState.IMOVING;
        lastX = me.getX();
        lastY = me.getY();
        }

        public void mouseReleased(MouseEvent me)
        {
        setCursor(Cursor.getDefaultCursor());
        state = PanelState.IDLE;
        }
    });

    addMouseMotionListener(new MouseMotionAdapter() {
        public void mouseDragged(MouseEvent me)
        {
        doImageMoved(me);
        }
    });
    }

    public ImagePanel(BufferedImage bi)
    {
    theImage = bi;
    preferredSize = new Dimension(theImage.getWidth(), theImage.getHeight());
    }

    public Dimension getPreferredSize()
    {
    return preferredSize;
    }

    private void doComponentChanged(HierarchyEvent he)
    {
    if (isShowing()) {
        panelLastLoc = getLocationOnScreen();
    }
    state = PanelState.IDLE;
    }

    private void doImageMoved(MouseEvent me)
    {
    if (!isShowing() || theImage == null)
        return;

    switch (state)
    {
        case RESIZING:
        error("IMOVING->RESIZING");
        break;
        case PMOVING:
        error("IMOVING->PMOVING");
        break;
        case IDLE:
        error("IMOVING->IDLE");
        break;
        case IMOVING:
        if (contains(me.getX(), me.getY())) {
            int dx = me.getX() - lastX;
            int dy = me.getY() - lastY;
            lastX = me.getX();
            lastY = me.getY();
            deltaLoc.x += dx;
            deltaLoc.y += dy;
            repaint();
        }
        return;
    }

    }

    private void doComponentMoved()
    {
    if (!isShowing() || theImage == null)
        return;

    switch (state)
    {
        case RESIZING:
        return;
        case IMOVING:
        error("IMOVING->PMOVING");
        break;
        case PMOVING:
        case IDLE:
        panelLastLoc = getLocationOnScreen();
        state = PanelState.PMOVING;
    }
    return;
    }

    private void doAncestorResizing()
    {
    if (!isShowing() || theImage == null)
        return;

    switch (state)
    {
        case IMOVING:
        error("IMOVING->RESIZING");
        return;
        case RESIZING:
        case PMOVING:
        case IDLE:
        Point cLoc = getLocationOnScreen();
        state = PanelState.RESIZING;
        if (theImage != null) {
            deltaLoc.x -= cLoc.x - panelLastLoc.x;
            deltaLoc.y -= cLoc.y - panelLastLoc.y;
        }
        panelLastLoc = cLoc;
    }
    }

    private void doComponentResized()
    {
    Point cLoc = getLocationOnScreen();
    switch (state)
    {
        case RESIZING:
        state = PanelState.IDLE;
        break;
        case IMOVING:
        error("IMOVING->RESIZED");
        break;
        case PMOVING:
        state = PanelState.IDLE;
        break;
        case IDLE:
        break;
    }

    if (theImage != null) {
        deltaLoc.x -= cLoc.x - panelLastLoc.x;
        deltaLoc.y -= cLoc.y - panelLastLoc.y;
    }
    panelLastLoc = cLoc;
    }

    public void setImage(BufferedImage nI)
    {
    theImage = nI;
    scaleF = 1.0;
    state = PanelState.IDLE;
    deltaLoc = new Point2D.Double(Math.round((getWidth() - theImage.getWidth()) / 2.0),
        Math.round((getHeight() - theImage.getHeight()) / 2.0));
    panelLastLoc = getLocationOnScreen();
    }

    private void error(String em)
    {
    System.err.println(em);
    System.exit(1);
    }

    public void paintComponent(Graphics g)
    {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    if (theImage == null)
        return;
    /*
     * Check if the viewport has resized or moved. The check below is
     * performed on every repaint.
     */

    Point cLoc = getLocationOnScreen();
    Dimension cDim = getSize();

    if (state == PanelState.RESIZING || state == PanelState.IDLE) {
        deltaLoc.x -= cLoc.x - panelLastLoc.x;
        deltaLoc.y -= cLoc.y - panelLastLoc.y;
    }
    /*
    System.err.println("image left edge= "
        + Math.round(cLoc.x + deltaLoc.x) + "; state= " + state
        + "; cDim= " + cDim + "; cLoc= " + cLoc + "; pLLoc= "
        + panelLastLoc + "; dLoc= " + deltaLoc);
        */
    // In all cases update panelLastLoc
    panelLastLoc = cLoc;

    g2.drawImage(theImage, (int) Math.round(deltaLoc.x),
        (int) Math.round(deltaLoc.y), null);
    }
}
4

2 に答える 2

0

画像をオーバーライドして(または多分)paintComponent呼び出すことを試みましたか?これにより、変更後に画面に何かが表示される前に呼び出されるようになります。repaintrevalidatedrawImage

この質問も参照してください。

于 2012-05-22T23:52:26.143 に答える
0

答えではありませんが、共有したいと思った失敗した試みです。必要に応じて反対票を投じてください。

私は賢く、JLabel/ImageIcon を保持する JScrollPane を使用して移動しようと考えましたが、それでもうまくいきませんでした。たとえば、

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class ImageViewer2 extends JPanel {
   private static final int SP_WIDTH = 500;
   private static final int SP_HEIGHT = SP_WIDTH;
   private JLabel viewportView = new JLabel();
   private JViewport viewport = new JViewport();
   private JScrollPane scrollpane = new JScrollPane();
   private Point viewLocOnScrn = null;

   public ImageViewer2() {
      viewport.setView(viewportView);
      scrollpane.setViewport(viewport);
      viewport.setBackground(Color.gray);
      viewport.addComponentListener(new MyComponentListener());

      scrollpane.setPreferredSize(new Dimension(SP_WIDTH, SP_HEIGHT));
      scrollpane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
      scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);

      MyMouseAdapter mouseAdapter = new MyMouseAdapter();
      viewport.addMouseListener(mouseAdapter);
      viewport.addMouseMotionListener(mouseAdapter);

      JButton loadImageBtn = new JButton(new LoadImageAction("Load Image"));
      JPanel topPanel = new JPanel();
      topPanel.add(loadImageBtn);

      setLayout(new BorderLayout());
      add(scrollpane, BorderLayout.CENTER);
      add(topPanel, BorderLayout.PAGE_START);
   }

   private class MyComponentListener extends ComponentAdapter {

      @Override
      public void componentMoved(ComponentEvent compEvt) {
         compEvtOccurred(compEvt);
      }

      @Override
      public void componentResized(ComponentEvent compEvt) {
         compEvtOccurred(compEvt);
      }

      private void compEvtOccurred(ComponentEvent compEvt) {
         Point newViewLocOnScn = viewportView.getLocationOnScreen();
         if (viewLocOnScrn != null && !newViewLocOnScn.equals(viewLocOnScrn)) {
            Point scrollPaneLocOnScrn = scrollpane.getLocationOnScreen();
            int x = scrollPaneLocOnScrn.x - viewLocOnScrn.x;
            int y = scrollPaneLocOnScrn.y - viewLocOnScrn.y;
            viewport.setViewPosition(new Point(x, y));
         }
      }

   }

   private class MyMouseAdapter extends MouseAdapter {
      private Point delta;

      @Override
      public void mousePressed(MouseEvent mEvt) {
         Point mousePt = mEvt.getPoint();
         Point viewPos = viewport.getViewPosition();
         delta = new Point(viewPos.x + mousePt.x, viewPos.y + mousePt.y);
      }

      @Override
      public void mouseDragged(MouseEvent e) {
         if (delta ==  null ) {
            return;
         }

         Point p = e.getPoint();
         viewport.setViewPosition(new Point(delta.x - p.x, delta.y - p.y));
         viewLocOnScrn = viewportView.getLocationOnScreen();
      }

      @Override
      public void mouseReleased(MouseEvent e) {
         delta = null;
      }
   }

   private class LoadImageAction extends AbstractAction {
      public LoadImageAction(String text) {
         super(text);
      }

      @Override
      public void actionPerformed(ActionEvent actEvt) {
         JFileChooser jfc = new JFileChooser("img003.jpg");
         int jfcResult = jfc.showOpenDialog(ImageViewer2.this);
         if (jfcResult == JFileChooser.APPROVE_OPTION) {
            File file = jfc.getSelectedFile();
            try {
               BufferedImage bufImg = ImageIO.read(file);
               ImageIcon icon = new ImageIcon(bufImg);
               viewportView.setIcon(icon);
               Dimension vpSize = viewport.getSize();
               int vpX = (bufImg.getWidth() - vpSize.width) / 2;
               int vpY = (bufImg.getHeight() - vpSize.height) / 2;
               Point viewPos = new Point(vpX, vpY);
               viewport.setViewPosition(viewPos);
               viewLocOnScrn = viewportView.getLocationOnScreen();
            } catch (IOException e) {
               e.printStackTrace();
            }

         }

      }
   }

   private static void createAndShowGui() {
      ImageViewer2 mainPanel = new ImageViewer2();

      JFrame frame = new JFrame("Image Viewer 2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

コメントと批判を歓迎します!

于 2012-05-24T04:45:26.277 に答える