JPanel - Problems replacing the currently displayed image with a new thumbnail

I am trying to create a graphic component that allows me to draw a single rectangle on a selected image (the rectangle must be drawn using drag and drop operations): the purpose of this component is to obtain the coordinates and size of the rectangle's drawing; the second goal is to provide a component that can be easily integrated into a graphical user interface.

The authors of this example created a subclass JLabelfor drawing the image, then they added MouseInputAdapterto the instance of this subclass to deal with the drawing of the rectangle.

I was inspired by this example, with the difference that I created a subclass of the class JPanel: I called it a class FigurePanel. Then I made some changes to provide the following features:

  • If the image is larger than the instance FigurePanel, then scrollers should appear;
  • If the image is smaller than the instance FigurePanel, then this image should be placed in the center of the panel;
  • while the user draws a rectangle, he should not go beyond the image.

Here is the source code for the class FigurePanel.

package imageselectionproject;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;


public class FigurePanel extends JPanel
{
    private Image backgroundImage = null;
    private Rectangle imageLimits = new Rectangle(0, 0, getWidth(), getHeight());

    private Rectangle currentRect = null;
    private Rectangle rectToDraw = null;
    private final Rectangle previousRectDrawn = new Rectangle();


    public FigurePanel()
    {
        setOpaque(true);

        SelectionListener listener = new SelectionListener();
        addMouseListener(listener);
        addMouseMotionListener(listener);
    }

    @Override
    public Dimension getPreferredSize()
    {
        return backgroundImage == null ? super.getPreferredSize() : new Dimension(backgroundImage.getWidth(this), backgroundImage.getHeight(this));
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g); //paints the background and image

        if (backgroundImage != null)
        {
            g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
        }

        // If currentRect exists, paint a box on top.
        if (currentRect != null)
        {
            // Draw a rectangle on top of the image.
            g.setXORMode(Color.white); // Color of line varies
                                       // depending on image colors
            g.drawRect(rectToDraw.x, rectToDraw.y, 
                       rectToDraw.width - 1, rectToDraw.height - 1);

            System.out.println(rectToDraw);
        }
    }


    public void setImage(Image image)
    {
        int x = 0;
        int y = 0;

        if (image != null)
        {
            backgroundImage = image;

            // The following instructions are used to center the image on the panel.
            /*x = (getSize().width - image.getWidth(this)) / 2;
            y = (getSize().height - image.getHeight(this)) / 2;

            if (x < 0) x = 0;
            if (y < 0) y = 0;*/
        }
        else
        {
            backgroundImage = null;
        }

        currentRect = null;

        setSize(getPreferredSize());
        imageLimits.setBounds(x, y, getWidth(), getHeight());
        System.out.println("imageLimits = " + imageLimits);

        repaint();
    }

    private void updateDrawableRect()
    {
        int x = currentRect.x;
        int y = currentRect.y;
        int width = currentRect.width;
        int height = currentRect.height;

        // Make the width and height positive, if necessary.
        if (width < 0)
        {
            width = 0 - width;
            x = x - width + 1;
            if (x < 0)
            {
                width += x;
                x = 0;
            }
        }
        if (height < 0)
        {
            height = 0 - height;
            y = y - height + 1;
            if (y < 0)
            {
                height += y;
                y = 0;
            }
        }

        // The rectangle should not extend beyond the boundaries of the image.
        if (x < imageLimits.x)
        {
            width -= (imageLimits.x - x);
            x = imageLimits.x;
        }
        else if ((x + width) > imageLimits.x + imageLimits.width)
        {
            width = imageLimits.x + imageLimits.width - x;
        }
        if (y < imageLimits.y)
        {
            height -= (imageLimits.y - y);
            y = imageLimits.y;
        }
        if ((y + height) > imageLimits.y + imageLimits.height)
        {
            height = imageLimits.y + imageLimits.height - y;
        }

        // Update rectToDraw after saving old value.
        if (rectToDraw != null)
        {
            previousRectDrawn.setBounds(rectToDraw.x, rectToDraw.y, 
                                        rectToDraw.width, rectToDraw.height);
            rectToDraw.setBounds(x, y, width, height);
        }
        else
        {
            rectToDraw = new Rectangle(x, y, width, height);
        }
    }

    private class SelectionListener extends MouseInputAdapter
    {
        @Override
        public void mousePressed(MouseEvent e)
        {
            int x = e.getX();
            int y = e.getY();
            currentRect = new Rectangle(x, y, 0, 0);
            updateDrawableRect();
            repaint();
        }

        @Override
        public void mouseDragged(MouseEvent e)
        {
            updateSize(e.getX(), e.getY());
        }

        @Override
        public void mouseReleased(MouseEvent e)
        {
            updateSize(e.getX(), e.getY());
        }

        /* 
         * Update the size of the current rectangle
         * and call repaint.  Because currentRect
         * always has the same origin, translate it
         * if the width or height is negative.
         * 
         * For efficiency (though
         * that isn't an issue for this program),
         * specify the painting region using arguments
         * to the repaint() call.
         * 
         */
        void updateSize(int x, int y)
        {
            currentRect.setSize(x - currentRect.x, y - currentRect.y);
            updateDrawableRect();

            Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
            repaint(totalRepaint.x, totalRepaint.y,
                    totalRepaint.width, totalRepaint.height);
        }
    }

}

The method is setImageused to set a new image, so it calls the method repaintto redraw the graphic component. In the above code, I disabled (through comments) the instructions for centering the image: thus, the component works fine.

, , , , , : , , , , , , ; , .

? ?

FigurePanelTest FigurePanel.

package imageselectionproject;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;


public class FigurePanelTest extends JFrame
{
    public FigurePanelTest()
    {
        FigurePanel imagePanel = new FigurePanel();

        JScrollPane imageScrollPane = new JScrollPane();
        imageScrollPane.setPreferredSize(new Dimension(420, 250));
        imageScrollPane.setViewportView(imagePanel);

        JButton imageButton = new JButton("Load Image");
        imageButton.addActionListener(
                new ActionListener()
                {
                    @Override
                    public void actionPerformed(ActionEvent evt)
                    {
                        JFileChooser fc = new JFileChooser();
                        int returnValue = fc.showOpenDialog(null);
                        if (returnValue == JFileChooser.APPROVE_OPTION) {
                            File selectedFile = fc.getSelectedFile();
                            System.out.println(selectedFile.getName());

                            try
                            {
                                Image image = ImageIO.read(selectedFile.getAbsoluteFile());
                                imagePanel.setImage(image);

                                imageScrollPane.getViewport().setViewPosition(new Point(0, 0));
                            }
                            catch(IOException e)
                            {
                                e.printStackTrace();
                            }
                        }
                    }
                }
        );

        Container container = getContentPane();
        container.setLayout(new FlowLayout());
        container.add(imageScrollPane);
        container.add(imageButton);

        setSize(600, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

}

.

public static void main(String args[]) {
        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new FigurePanelTest().setVisible(true);
            }
        });
    }

:

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.MouseInputAdapter;

public class TestDrawPanel {
   public static void main(String args[]) {
      /* Create and display the form */
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            new FigurePanelTest().setVisible(true);
         }
      });
   }
}

class FigurePanelTest extends JFrame {
   public FigurePanelTest() {
      final FigurePanel imagePanel = new FigurePanel();

      final JScrollPane imageScrollPane = new JScrollPane();
      imageScrollPane.setPreferredSize(new Dimension(420, 250));
      imageScrollPane.setViewportView(imagePanel);

      JButton imageButton = new JButton("Load Image");
      imageButton.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent evt) {
            JFileChooser fc = new JFileChooser();
            int returnValue = fc.showOpenDialog(null);
            if (returnValue == JFileChooser.APPROVE_OPTION) {
               File selectedFile = fc.getSelectedFile();
               System.out.println(selectedFile.getName());

               try {
                  Image image = ImageIO.read(selectedFile.getAbsoluteFile());
                  imagePanel.setImage(image);

                  imageScrollPane.getViewport()
                        .setViewPosition(new Point(0, 0));
               } catch (IOException e) {
                  e.printStackTrace();
               }
            }
         }
      });

      Container container = getContentPane();
      container.setLayout(new FlowLayout());
      container.add(imageScrollPane);
      container.add(imageButton);

      setSize(600, 400);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   }

}

class FigurePanel extends JPanel {
   private Image backgroundImage = null;
   private Rectangle imageLimits = new Rectangle(0, 0, getWidth(), getHeight());

   private Rectangle currentRect = null;
   private Rectangle rectToDraw = null;
   private final Rectangle previousRectDrawn = new Rectangle();

   public FigurePanel() {
      setOpaque(true);

      SelectionListener listener = new SelectionListener();
      addMouseListener(listener);
      addMouseMotionListener(listener);
   }

   @Override
   public Dimension getPreferredSize() {
      return backgroundImage == null ? super.getPreferredSize()
            : new Dimension(backgroundImage.getWidth(this),
                  backgroundImage.getHeight(this));
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g); // paints the background and image

      if (backgroundImage != null) {
         g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
      }

      // If currentRect exists, paint a box on top.
      if (currentRect != null) {
         // Draw a rectangle on top of the image.
         g.setXORMode(Color.white); // Color of line varies
                                    // depending on image colors
         g.drawRect(rectToDraw.x, rectToDraw.y, rectToDraw.width - 1,
               rectToDraw.height - 1);

         System.out.println(rectToDraw);
      }
   }

   public void setImage(Image image) {
      int x = 0;
      int y = 0;

      if (image != null) {
         backgroundImage = image;

         // The following instructions are used to center the image on the
         // panel.
         /*
          * x = (getSize().width - image.getWidth(this)) / 2; y =
          * (getSize().height - image.getHeight(this)) / 2;
          * 
          * if (x < 0) x = 0; if (y < 0) y = 0;
          */
      } else {
         backgroundImage = null;
      }

      currentRect = null;

      setSize(getPreferredSize());
      imageLimits.setBounds(x, y, getWidth(), getHeight());
      System.out.println("imageLimits = " + imageLimits);

      repaint();
   }

   private void updateDrawableRect() {
      int x = currentRect.x;
      int y = currentRect.y;
      int width = currentRect.width;
      int height = currentRect.height;

      // Make the width and height positive, if necessary.
      if (width < 0) {
         width = 0 - width;
         x = x - width + 1;
         if (x < 0) {
            width += x;
            x = 0;
         }
      }
      if (height < 0) {
         height = 0 - height;
         y = y - height + 1;
         if (y < 0) {
            height += y;
            y = 0;
         }
      }

      // The rectangle should not extend beyond the boundaries of the image.
      if (x < imageLimits.x) {
         width -= (imageLimits.x - x);
         x = imageLimits.x;
      } else if ((x + width) > imageLimits.x + imageLimits.width) {
         width = imageLimits.x + imageLimits.width - x;
      }
      if (y < imageLimits.y) {
         height -= (imageLimits.y - y);
         y = imageLimits.y;
      }
      if ((y + height) > imageLimits.y + imageLimits.height) {
         height = imageLimits.y + imageLimits.height - y;
      }

      // Update rectToDraw after saving old value.
      if (rectToDraw != null) {
         previousRectDrawn.setBounds(rectToDraw.x, rectToDraw.y,
               rectToDraw.width, rectToDraw.height);
         rectToDraw.setBounds(x, y, width, height);
      } else {
         rectToDraw = new Rectangle(x, y, width, height);
      }
   }

   private class SelectionListener extends MouseInputAdapter {
      @Override
      public void mousePressed(MouseEvent e) {
         int x = e.getX();
         int y = e.getY();
         currentRect = new Rectangle(x, y, 0, 0);
         updateDrawableRect();
         repaint();
      }

      @Override
      public void mouseDragged(MouseEvent e) {
         updateSize(e.getX(), e.getY());
      }

      @Override
      public void mouseReleased(MouseEvent e) {
         updateSize(e.getX(), e.getY());
      }

      /*
       * Update the size of the current rectangle and call repaint. Because
       * currentRect always has the same origin, translate it if the width or
       * height is negative.
       * 
       * For efficiency (though that isn't an issue for this program), specify
       * the painting region using arguments to the repaint() call.
       */
      void updateSize(int x, int y) {
         currentRect.setSize(x - currentRect.x, y - currentRect.y);
         updateDrawableRect();

         Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
         repaint(totalRepaint.x, totalRepaint.y, totalRepaint.width,
               totalRepaint.height);
      }
   }

}
+4
1

x y setImage(). . , x y

paintComponent,

 if (backgroundImage != null) {
        imageLimits.x = (this.getWidth() - backgroundImage.getWidth(this)) / 2;
        imageLimits.y = (this.getHeight() - backgroundImage.getHeight(this)) / 2;
        g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
    }
+4

Source: https://habr.com/ru/post/1598573/


All Articles