ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-06-23 17:47:27  阅读:169  来源: 互联网

标签:java image swing


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

this example的作者创建了JLabel的子类以绘制图像,然后他们将MouseInputAdapter添加到此子类的实例中以处理矩形的绘制.

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

>如果图像大于FigurePanel的实例,则必须出现滚动条;
>如果图像小于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);
        }
    }

}

方法setImage用于设置新图像,因此它调用方法重绘以重绘图形组件.在上面显示的代码中,我禁用(通过注释)指令使图像居中:这样,组件似乎正常工作.

相反,如果我启用这样的指令,当图像小于面板本身时,图像正确定位在面板的中心,但是,我遇到了以下问题:假设它当前显示的图像大于面板,如果我决定加载的新图像小于当前显示的图像,则不显示新图像;如果我尝试重新加载新图像,则会出现.

为什么会出现这个问题?怎么解决?

我还创建了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);
      }
   }

}

解决方法:

问题是计算setImage()中的x和y.它没有正确计算面板的中心.我是通过多次加载小图像和大图像后检查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);
    }

标签:java,image,swing
来源: https://codeday.me/bug/20190623/1273241.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有