简体   繁体   English

将JPanel保存为图像(对象)并将其绘制回JPanel

[英]Saving a JPanel as an Image (object) and drawing it back onto a JPanel

I've had a look around and tried using other queries, but I just can't seem to get this to work. 我环顾四周并尝试使用其他查询,但似乎无法正常工作。

I am trying to retain an image from a JPanel drawn via the g.draw/fill methods. 我试图保留通过g.draw / fill方法绘制的JPanel的图像。

I've attempted to save the drawing in a buffered image, but when I display it in a messageDialog all I get is the background and none of the drawings 我试图将图形保存在缓冲的图像中,但是当我在messageDialog中显示它时,我得到的只是背景,没有一个图形

These two methods are the important code (from the DrawingPanel class): 这两个方法是重要的代码(来自DrawingPanel类):

        public void loadDrawing(BufferedImage bi) {
            //opens a message dialog and displays the image parameter
            JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
            System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
        }

        public BufferedImage getScreenShot() {

            BufferedImage image = new BufferedImage(this.getWidth(),
                    this.getHeight(), BufferedImage.TYPE_INT_RGB);
            // call the Panels's paint method, using
            // the Graphics object of the image.
            this.paint(image.getGraphics());
            return image;
        }

They get called here: 他们在这里打来电话:

        @Override
    public void actionPerformed(ActionEvent ae) {
        BufferedImage bi = dp.getScreenShot();
        dp.loadDrawing(bi);
    }

Here is the whole program, it should run. 这是整个程序,它应该运行。

      import java.awt.BorderLayout;
      import java.awt.Color;
      import java.awt.Graphics;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.awt.event.MouseEvent;
      import java.awt.event.MouseListener;
      import java.awt.event.MouseMotionListener;
      import java.awt.image.BufferedImage;
      import javax.swing.ImageIcon;
      import javax.swing.JButton;
      import javax.swing.JFrame;
      import javax.swing.JLabel;
      import javax.swing.JOptionPane;
      import javax.swing.JPanel;

public class TestClass extends JFrame implements ActionListener {

    DrawingPanel dp;

    public TestClass() {
        setSize(400, 400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel top = new JPanel();
        JButton load = new JButton("Load Image");
        load.addActionListener(this);
        top.add(load);

        dp = new DrawingPanel();
        dp.setBackground(Color.CYAN);

        add(top, BorderLayout.NORTH);
        add(dp, BorderLayout.CENTER);
        setVisible(true);
    }

    public static void main(String[] args) {
        new TestClass();
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        BufferedImage bi = dp.getScreenShot();
        dp.loadDrawing(bi);
    }

    private class DrawingPanel extends JPanel implements 
      MouseListener, MouseMotionListener {

        private int xPos, yPos;//mouse positions

        private DrawingPanel() {
            addMouseListener(this);
            addMouseMotionListener(this);
        }

        @Override
        public void mousePressed(MouseEvent me) {
            xPos = me.getX();
            yPos = me.getY();
        }

        @Override
        public void mouseDragged(MouseEvent me) {
            int x = me.getX(), y = me.getY();
            Graphics g = getGraphics();
            g.setColor(Color.BLACK);
            g.drawOval(xPos, yPos, 30, 30);
            xPos = x;
            yPos = y;
        }

        public void loadDrawing(BufferedImage bi) {
            //opens a message dialog and displays the image parameter
            JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
            System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
        }

        public BufferedImage getScreenShot() {

            BufferedImage image = new BufferedImage(this.getWidth(),
                    this.getHeight(), BufferedImage.TYPE_INT_RGB);
            // call the Panels's paint method, using
            // the Graphics object of the image.
            this.paint(image.getGraphics());
            return image;
        }

        //unused abstract method
        @Override
        public void mouseClicked(MouseEvent me) {
        }

        @Override
        public void mouseReleased(MouseEvent me) {
        }

        @Override
        public void mouseEntered(MouseEvent me) {
        }

        @Override
        public void mouseExited(MouseEvent me) {
        }

        @Override
        public void mouseMoved(MouseEvent me) {
        }
    }
}

I need to be able to store the graphics from the panel and retrieve it. 我需要能够从面板中存储图形并检索它。

Help would be heavily appreciated. 帮助将不胜感激。

Your getting your Graphics object by calling getGraphics() on a component, and images drawn with this will not persist. 通过在组件上调用getGraphics()来获取Graphics对象,使用该对象绘制的图像将不会保留。 Why not instead draw to a BufferedImage with its Graphics object, and then simply save that BufferedImage. 为什么不使用它的 Graphics对象绘制一个BufferedImage,然后简单地保存该BufferedImage呢? This would simplify things greatly, and your program would work. 这样可以大大简化事情,并且您的程序可以运行。

For example: 例如:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class TestClass2 extends JPanel {
   private DrawingPanel drawingPanel = new DrawingPanel();

   public TestClass2() {     
      JPanel northPanel = new JPanel();
      northPanel.add(new JButton(new GetImageAction("Get Image")));
      northPanel.add(new JButton(new ClearImageAction("Clear Image")));

      setLayout(new BorderLayout(5, 5));
      add(drawingPanel, BorderLayout.CENTER);
      add(northPanel, BorderLayout.NORTH);

   }

   private class GetImageAction extends AbstractAction {
      public GetImageAction(String name) {
         super(name);
         putValue(MNEMONIC_KEY, KeyEvent.VK_G);
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         BufferedImage img = drawingPanel.getMainImage();
         ImageIcon icon = new ImageIcon(img);
         JOptionPane.showMessageDialog(TestClass2.this, icon);
      }
   }

   private class ClearImageAction extends AbstractAction {
      public ClearImageAction(String name) {
         super(name);
         putValue(MNEMONIC_KEY, KeyEvent.VK_C);
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         drawingPanel.clearImage();
         drawingPanel.repaint();
      }
   }


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

      JFrame frame = new JFrame("TestClass2");
      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();
         }
      });
   }
}

class DrawingPanel extends JPanel {
   public static final int BI_WIDTH = 400;
   public static final int BI_HEIGHT = BI_WIDTH;
   private static final Color BACKGROUND = Color.CYAN;
   public static final Color DRAW_COLOR = Color.black;
   public static final int OVAL_WIDTH = 30;
   private BufferedImage mainImage;

   public DrawingPanel() {
      MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
      addMouseListener(myMouseAdapter);
      addMouseMotionListener(myMouseAdapter);
      clearImage();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (mainImage != null) {
         g.drawImage(mainImage, 0, 0, this);
      }
   }

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

   public BufferedImage getMainImage() {
      return mainImage;
   }

   public void clearImage() {
      mainImage = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB);
      Graphics g = mainImage.getGraphics();
      g.setColor(BACKGROUND);
      g.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
      g.dispose();
   }

   private class MyMouseAdapter extends MouseAdapter {

      @Override
      public void mousePressed(MouseEvent mEvt) {
         draw(mEvt);
      }

      @Override
      public void mouseDragged(MouseEvent mEvt) {
         draw(mEvt);
      }

      private void draw(MouseEvent mEvt) {
         Graphics2D g2 = mainImage.createGraphics();
         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
               RenderingHints.VALUE_ANTIALIAS_ON);
         g2.setColor(DRAW_COLOR);
         g2.drawOval(mEvt.getX() - OVAL_WIDTH / 2, mEvt.getY() - OVAL_WIDTH / 2, OVAL_WIDTH, OVAL_WIDTH);
         g2.dispose();
         repaint();
      }
   }

}

Every attempt to draw something into the Graphics object that was obtained from a Component by calling getGraphics will fail sooner or later. 通过调用getGraphicsComponent获得的将某些东西绘制到Graphics对象中的任何尝试都会迟早失败。 This Graphics object merely serves as a "path" to the actual screen (that is only valid while the component is actually painted on the screen). Graphics对象仅充当实际屏幕的“路径”(仅在组件实际绘制在屏幕上时才有效)。 It is not a "buffer", and it does not "store" anything that was drawn. 它不是“缓冲区”,也不“存储”绘制的任何内容。

If you want to create a simple painting program, you should draw to a BufferedImage . 如果要创建一个简单的绘画程序,则应绘制到BufferedImage And when the DrawingPanel is to be painted, you only paint this BufferedImage . 当绘制DrawingPanel时,只需绘制此BufferedImage The additional advantage here is that when you want to make a screenshot, you basically just have to return a copy of this BufferedImage . 这里的另一个优点是,当您要制作屏幕截图时,基本上只需要返回此BufferedImage的副本即可。

I sketeched the basic approach in your DrawingPanel class, with some in-lined comments. 我在您的DrawingPanel类中添加了一些内联注释,从而简化了基本方法。 It could be cleaned up and beautified, and there are some aspects to consider (eg what should happen when the DrawingPanel is resized?), but it shows how it should work in general: 可以对其进行清理和美化,并且需要考虑一些方面(例如,调整DrawingPanel的大小时会发生什么?),但它总体上显示了其工作方式:

private class DrawingPanel extends JPanel implements 
    MouseListener, MouseMotionListener {

    // The image that will store what was drawn. In the
    // mouseDragged method, the painting operations will
    // go directly to this image. When this panel is
    // painted, then ONLY this image will be painted.
    private BufferedImage bufferedImage;

    private int xPos, yPos;//mouse positions

    private DrawingPanel() {
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    // Make sure that the "bufferedImage" is non-null
    // and has the same size as this panel
    private void validateImage()
    {
        if (bufferedImage == null)
        {
            bufferedImage = new BufferedImage(
                getWidth(), getHeight(), 
                BufferedImage.TYPE_INT_ARGB);
            Graphics g = bufferedImage.getGraphics();
            g.setColor(getBackground());
            g.fillRect(0,0,getWidth(),getHeight());
            g.dispose();

        }
        if (bufferedImage.getWidth() != getWidth() ||
            bufferedImage.getHeight() != getHeight())
        {
            BufferedImage newBufferedImage = new BufferedImage(
                getWidth(), getHeight(), 
                BufferedImage.TYPE_INT_ARGB);
            Graphics g = newBufferedImage.getGraphics();
            g.setColor(getBackground());
            g.fillRect(0,0,getWidth(),getHeight());
            g.drawImage(bufferedImage, 0,0,null);
            g.dispose();
            bufferedImage = newBufferedImage;
        }
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        validateImage();

        // Paint the bufferedImage which stores
        // what was drawn until now
        g.drawImage(bufferedImage, 0, 0, null);
    }


    @Override
    public void mousePressed(MouseEvent me) {
        xPos = me.getX();
        yPos = me.getY();
    }


    @Override
    public void mouseDragged(MouseEvent me) {
        int x = me.getX(), y = me.getY();
        validateImage();

        // Paint directly into the bufferedImage here
        Graphics g = bufferedImage.getGraphics();
        g.setColor(Color.BLACK);
        g.drawOval(xPos, yPos, 30, 30);
        repaint();
        xPos = x;
        yPos = y;
    }

    public void loadDrawing(BufferedImage bi) {
        //opens a message dialog and displays the image parameter
        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
        System.out.println("w:" + bi.getWidth() + " h:" + bi.getHeight());
    }

    public BufferedImage getScreenShot() {

        // This basically returns a "copy" of the
        // bufferedImage that stores what was drawn
        BufferedImage image = new BufferedImage(
            getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        g.drawImage(bufferedImage, 0, 0, null);
        g.dispose();
        return image;
    }

    //unused abstract method
    @Override
    public void mouseClicked(MouseEvent me) {
    }

    @Override
    public void mouseReleased(MouseEvent me) {
    }

    @Override
    public void mouseEntered(MouseEvent me) {
    }

    @Override
    public void mouseExited(MouseEvent me) {
    }

    @Override
    public void mouseMoved(MouseEvent me) {
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM