Сохранение JPanel как изображения (объекта) и отрисовка его на JPanel

1

Я осмотрелся и попробовал использовать другие запросы, но я просто не могу заставить это работать.

Я пытаюсь сохранить изображение из JPanel, нарисованного методами g.draw/fill.

Я попытался сохранить чертеж в буферизованном изображении, но когда я показываю его в сообщенииDialog, все, что я получаю, это фон и ни один из рисунков

Эти два метода - важный код (из класса 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 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 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) {
        }
    }
}

Мне нужно иметь возможность хранить графику с панели и извлекать ее.

Помощь будет в значительной степени оценена.

Теги:
graphics
swing
jpanel
paint

2 ответа

3
Лучший ответ

Каждая попытка сделать что-то в объекте Graphics, полученном из Component, вызвав getGraphics не удастся рано или поздно. Этот объект Graphics просто служит в качестве "пути" к фактическому экрану (который действителен только тогда, когда компонент фактически нарисован на экране). Это не "буфер", и он не "хранит" все, что было нарисовано.

Если вы хотите создать простую программу рисования, вам следует нарисовать BufferedImage. И когда DrawingPanel должен быть нарисован, вы только DrawingPanel этот BufferedImage. Дополнительным преимуществом здесь является то, что, когда вы хотите сделать снимок экрана, вам просто нужно вернуть копию этого BufferedImage.

Я набросал базовый подход в вашем классе DrawingPanel с некоторыми 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) {
    }
}
  • 0
    Это как раз то, что мне было нужно, спасибо.
  • 0
    Отлично сработано. 1+ до голосования.
Показать ещё 2 комментария
3

Вы получаете свой объект Graphics, вызывая getGraphics() на компоненте, и образы, нарисованные с этим, не будут сохраняться. Почему бы не обратить внимание на BufferedImage с его объектом Graphics, а затем просто сохранить 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();
      }
   }

}
  • 0
    Я пытался сделать это раньше, но не смог изменить размер BufferedImage с помощью JPanel. Я пойду еще раз и дам вам ответ, если я заставлю его работать.
  • 0
    @ user3061132: см. пример программы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню