如何保存在 JPanel 中绘制的线条?

How can I save the lines painted in a JPanel?

我最初是在寻找一个库来为 java 制作 "mousewritten" 或 "handwritten" 签名。我没有找到任何东西,所以我只是想让用户在 JPanel 上绘制 canvas,然后他可以选择保存、重新绘制或取消签名。我遇到的问题是,当我试图将绘制的东西保存在 canvas 中时,我得到一个空的 .jpeg

到目前为止我的代码:

import javax.swing.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.colorchooser.*;
import javax.swing.event.*;

import java.awt.geom.Line2D;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.logging.Logger;

import javax.imageio.ImageIO;


public class AES_Encryption extends JFrame implements ActionListener{



public BufferedImage image = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
//JPanel canvas = new JPanel();

    JPanel buttonPanel = new JPanel();
    Point lastPos = null;
    Point startPos = null;
    Point finishPos = null;
    Graphics g;
    JButton save = new JButton("Save");
    JButton cancel = new JButton("Cancel");
    JButton clear = new JButton("Clear");
    JPanel canvas = new JPanel();
    int changer = 1;
    String path="";

    public AES_Encryption () {


        setLocation(100,100);
        setSize(600,500);
        setTitle("ENCODE SECTION");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        canvas.setBackground(Color.WHITE);

        clear.addActionListener(this);
        clear.setActionCommand("clear");

        save.addActionListener(this);
        save.setActionCommand("Save");


        cancel.addActionListener(this);
        cancel.setActionCommand("Cancel");


        //add buttons here

        buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
        buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
        buttonPanel.add(Box.createHorizontalGlue());
        buttonPanel.add(save);
        buttonPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        buttonPanel.add(clear);
        buttonPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        buttonPanel.add(cancel);

        //set the look
        getContentPane().add(canvas, BorderLayout.CENTER);
        getContentPane().add(buttonPanel, BorderLayout.SOUTH);
        setVisible(true);

        g = canvas.getGraphics();
        g.setColor(Color.BLACK);

        canvas.addMouseMotionListener(new MouseMotionListener () {                      
            public void mouseDragged (MouseEvent m) {
                Point p = m.getPoint() ;
                if (changer==1){
                g.drawLine(lastPos.x, lastPos.y, p.x, p.y) ;
                }           
                lastPos = p ;

            }   
            public void mouseMoved (MouseEvent m) {}
        });

        canvas.addMouseListener(new MouseListener () {
            public void mouseClicked(MouseEvent e) {startPos = e.getPoint();}
            public void mousePressed(MouseEvent e) {lastPos = e.getPoint();}
            public void mouseReleased(MouseEvent e) {
            lastPos = null; 
            finishPos = e.getPoint(); 
            startPos = null;}
            public void mouseEntered(MouseEvent e) {}
            public void mouseExited(MouseEvent e) {}
            });


    }



    public void actionPerformed(ActionEvent e) {
        if("clear".equals(e.getActionCommand())) {
            repaint();
        }
        if("Save".equals(e.getActionCommand())) {
            captureCanvasImage myCanvas = new captureCanvasImage();
            myCanvas.capture();
        }
        if("Cancel".equals(e.getActionCommand())) {
            dispose();
        }}


    class captureCanvasImage {
        public void capture(){
            BufferedImage imagebuf=null;
            try {
                imagebuf = new Robot().createScreenCapture(canvas.bounds());
            } catch (AWTException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }  
             Graphics2D graphics2D = imagebuf.createGraphics();
             canvas.paint(graphics2D);
             try {
                ImageIO.write(imagebuf,"jpeg", new File("save1.jpeg"));
            } catch (Exception e) {
                // TODO Auto-generated catch block
                System.out.println("error");
            }
    }

            }


    /*
    @Override
    public void invalidate() {     
    super.invalidate(); 

    this.paint(this.getGraphics()); 
    }
*/

    public static void main (String [] args) {
        AES_Encryption p = new AES_Encryption();
        p.setVisible(true);
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        p.setLocation(dim.width/2-p.getSize().width/2, dim.height/2-p.getSize().height/2);
    }
}

创建线的坐标时,将它们保存在列表中。


            List<Point> points = new ArrayList<>(); // instance field.

            canvas.addMouseMotionListener(new MouseMotionListener () {                      
            public void mouseDragged (MouseEvent m) {
                Point p = m.getPoint() ;
                if (changer==1){
                g.drawLine(lastPos.x, lastPos.y, p.x, p.y) ;
                points.add(lastPos);// add it here.
                }           
                lastPos = p ;

            }   
            public void mouseMoved (MouseEvent m) {}
        });

这是一个例子。您需要确定放置 points.add() 代码的位置。查看绘画示例here

已编辑:

这里有一个如何绘制window的例子。不要在 paintpaintComponent 等绘画环境之外使用图形上下文(例外情况是 buffered images 等,它们不会在 EDT 中绘画)。


    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.RenderingHints;
    import java.util.List;
    import java.util.Random;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;

    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;

    public class ExampleDrawDemo extends JPanel {

       int        WIDTH  = 600;
       int        HEIGHT = 500;
       JFrame     frame  = new JFrame();
       List<Line> lines;

       public static void main(String[] args) {
          SwingUtilities.invokeLater(() -> new ExampleDrawDemo().start());
       }
       public void start() {
          Random r = new Random();
          Color[] color = {
                Color.RED, Color.BLUE, Color.GREEN, Color.MAGENTA, Color.ORANGE,
                Color.CYAN
          };

          // generate some lines.
          lines = IntStream.range(0, 100).mapToObj(
                i -> new Line(r, color[r.nextInt(color.length)])).collect(
                      Collectors.toList());

          setPreferredSize(new Dimension(600, 500));
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.add(this);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }

       public void paintComponent(Graphics g) {
          super.paintComponent(g);
          Graphics2D g2d = (Graphics2D) g.create();
          // smooth lines
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                   RenderingHints.VALUE_ANTIALIAS_ON);
          // line thickness
          g2d.setStroke(new BasicStroke(2));

          for (Line line : lines) {
             g2d.setColor(line.color);
             g2d.drawLine(line.start.x, line.start.y, line.end.x, line.end.y);
          }
          g2d.dispose();
       }

       class Line {
          Point start;
          Point end;
          Color color;

          public Line(Random r, Color color) {
             this.color = color;
             start = new Point(r.nextInt(WIDTH), r.nextInt(HEIGHT));
             end = new Point(r.nextInt(WIDTH), r.nextInt(HEIGHT));
          }
       }
    }