提问者:小点点

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


我环顾四周,尝试使用其他查询,但我似乎无法让它工作。

我试图保留一个图像从一个JPanel绘制通过g.绘制/填充方法。

我试图将绘图保存在缓冲图像中,但是当我在消息对话框中显示它时,我得到的只是背景,没有任何绘图

这两个方法是重要的代码(来自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;
        }

他们在这里被称为:

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

这是整个程序,它应该运行。

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

我需要能够从面板中存储图形并检索它。

非常感谢帮助。


共2个答案

匿名用户

每次尝试通过调用getGraphicsComponent获得的Graphics对象中绘制某些内容迟早会失败。这个Graphics对象只是作为实际屏幕的“路径”(仅在组件实际绘制在屏幕上时有效)。它不是“缓冲区”,也不会“存储”任何绘制的内容。

如果你想创建一个简单的绘画程序,你应该绘制到一个BufferedImage。当DrawingPanel要绘制时,你只绘制这个BufferedImage。这里的额外好处是,当你想要制作屏幕截图时,你基本上只需要返回这个BufferedImage的副本。

我在您的DrawingPanel类中勾勒了基本方法,并带有一些内联注释。它可以被清理和美化,并且有一些方面需要考虑(例如,当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) {
    }
}

匿名用户

通过调用组件上的getGraphics()来获取Graphics对象,用它绘制的图像将不会持久。为什么不用它的Graphics对象绘制到BufferedImage,然后简单地保存该BufferedImage。这将大大简化事情,并且您的程序可以工作。

例如:

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

}

相关问题