Java JPanel-用新的较小图像替换当前显示的图像时出现问题

Java JPanel-用新的较小图像替换当前显示的图像时出现问题,java,image,swing,Java,Image,Swing,我正在尝试创建一个图形组件,允许我在选定的图像上绘制一个矩形(必须使用拖放操作绘制矩形):该组件的目的是获取绘制的矩形的坐标和大小;第二个目标是提供一个可以轻松集成到图形用户界面中的组件 的作者创建了JLabel的子类以绘制图像,然后他们向该子类的实例添加了MouseInputAdapter,以处理矩形的绘制 我受到这个例子的启发,不同的是我创建了一个JPanelclass的子类:我将它命名为FigurePanelclass。然后我做了一些更改,以提供以下功能: 如果图像大于FigurePan

我正在尝试创建一个图形组件,允许我在选定的图像上绘制一个矩形(必须使用拖放操作绘制矩形):该组件的目的是获取绘制的矩形的坐标和大小;第二个目标是提供一个可以轻松集成到图形用户界面中的组件

的作者创建了
JLabel
的子类以绘制图像,然后他们向该子类的实例添加了
MouseInputAdapter
,以处理矩形的绘制

我受到这个例子的启发,不同的是我创建了一个
JPanel
class的子类:我将它命名为
FigurePanel
class。然后我做了一些更改,以提供以下功能:

  • 如果图像大于
    FigurePanel
    的实例,则必须显示滚动条
  • 如果图像小于
    图面板的实例
    ,则此图像必须放置在面板的中心
  • 当用户绘制矩形时,它不应超出图像的限制
下面是
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);
        }
    }

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

对于Andrew,一个单一的程序:

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

}
导入java.awt.Color;
导入java.awt.Container;
导入java.awt.Dimension;
导入java.awt.FlowLayout;
导入java.awt.Graphics;
导入java.awt.Image;
导入java.awt.Point;
导入java.awt.Rectangle;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.MouseEvent;
导入java.awt.image.buffereImage;
导入java.io.File;
导入java.io.IOException;
导入javax.imageio.imageio;
导入javax.swing.JButton;
导入javax.swing.JFileChooser;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.JScrollPane;
导入javax.swing.event.MouseInputAdapter;
公共类TestDrawPanel{
公共静态void main(字符串参数[]){
/*创建并显示表单*/
invokeLater(new Runnable()){
公开募捐{
新的FigurePanelTest().setVisible(true);
}
});
}
}
类图PanelTest扩展了JFrame{
公众人物广告{
最终FigurePanel imagePanel=新FigurePanel();
final JScrollPane imageScrollPane=新JScrollPane();
设置PreferredSize(新维度(420250));
imageScrollPane.setViewportView(imagePanel);
JButton imageButton=新JButton(“加载图像”);
addActionListener(新建ActionListener()){
@凌驾
已执行的公共无效操作(操作事件evt){
JFileChooser fc=新的JFileChooser();
int returnValue=fc.showOpenDialog(null);
if(returnValue==JFileChooser.APPROVE\u选项){
File selectedFile=fc.getSelectedFile();
System.out.println(selectedFile.getName());
试一试{
Image=ImageIO.read(selectedFile.getAbsoluteFile());
imagePanel.setImage(图像);
imageScrollPane.getViewport()
.setViewPosition(新点(0,0));
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
});
Container=getContentPane();
container.setLayout(新的FlowLayout());
container.add(imageScrollPane);
容器。添加(图像按钮);
设置大小(600400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
类FigurePanel扩展了JPanel{
私有图像backgroundImage=null;
私有矩形imageLimits=新矩形(0,0,getWidth(),getHeight());
私有矩形currentRect=null;
私有矩形rectToDraw=null;
私有最终矩形PreviousRectDrawed=新矩形();
公共数字面板(){
set不透明(true);
SelectionListener=新建SelectionListener();
addMouseListener(监听器);
addMouseMotionListener(listener);
}
@凌驾
公共维度getPreferredSize(){
return backgroundImage==null?super.getPreferredSize()
:新尺寸(backgroundImage.getWidth(此),
backgroundImage.getHeight(this));
}
@凌驾
受保护组件(图形g){
super.paintComponent(g);//绘制背景和图像
if(backgroundImage!=null){
g、 drawImage(backgroundImage,imageLimits.x,imageLimits.y,this);
}
//如果currentRect存在,请在顶部绘制一个框。
if(currentRect!=null){
//在图像顶部绘制一个矩形。
g、 setXORMode(Color.white);//线条的颜色不同
//取决于图像颜色
g、 drawRect(rectToDraw.x,rectToDraw.y,rectToDraw.width-1,
rectToDraw.height-1);
System.out.println(rectToDraw);
}
}
公共void setImage(图像){
int x=0;
int y=0;
如果(图像!=null){
背景图像=图像;
//以下说明用于将图像居中放置在屏幕上
//小组。
/*
*x=(getSize().width-image.getWidth(this))/2;y=
*(getSize().height-image.getHeight(this))/2;
* 
*如果(x<0)x=0;如果(y<0)y=0;
*/
}否则{
backgroundImage=null;
}
currentRect=null;
设置大小(getPreferredSize());
setBounds(x,y,getWidth(),getHeight());
System.out.println(“imageLimits=“+imageLimits”);
重新油漆();
}
私有void updateDrawableRect(){
int x=currentRect.x;
int y=当前矩形y;
int width=currentRect.width;
int height=currentRect.height;
//加宽
 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);
    }