Java 如何让用户在画布内绘制并保存图像?

Java 如何让用户在画布内绘制并保存图像?,java,swing,canvas,jframe,drawing,Java,Swing,Canvas,Jframe,Drawing,我正在尝试实现一个徒手绘制的Java小程序,它允许用户在画布上绘制一些东西(画布不是优先级,它可以是其他任何东西,只要我可以在之后保存图像(需要保存它,因为我必须在按下按钮后在不同的位置显示它,欢迎任何其他解决方案))。我找到了一个代码,它允许我画画,但现在我在画布内画画时遇到了麻烦。。。我已经花了几天的时间没有结果了。以下是我目前掌握的代码及其描述: import java.awt.*; import java.awt.event.*; import java.awt.event.Ac

我正在尝试实现一个徒手绘制的Java小程序,它允许用户在画布上绘制一些东西(画布不是优先级,它可以是其他任何东西,只要我可以在之后保存图像(需要保存它,因为我必须在按下按钮后在不同的位置显示它,欢迎任何其他解决方案))。我找到了一个代码,它允许我画画,但现在我在画布内画画时遇到了麻烦。。。我已经花了几天的时间没有结果了。以下是我目前掌握的代码及其描述:

    import java.awt.*;
import java.awt.event.*;
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 javax.swing.*;
import java.applet.*;

public class paintMozApplet extends Applet implements ActionListener
{
    int xPressed,yPressed;
    int xReleased,yReleased;
    int xDragged,yDragged;
    private GridLayout gL;
    private JPanel buttons;
    private JPanel panel;
    private Button clear, createMoz;
    private Label  result_here;
    private javax.swing.JPanel drawing;
    private JPanel moz;
    private Canvas canvas;
    private draw draw;

    public paintMozApplet()
    {
        draw = new draw();

        gL = new GridLayout(1, 0);          

        buttons = new JPanel();
        drawing = new JPanel();
        moz = new JPanel();
        canvas = new Canvas();

        clear = new Button("clear");
        createMoz = new Button("Create Moz");

        buttons.add(clear);
        buttons.add(createMoz);

        result_here = new Label("Result here!");

        moz.add(result_here);
        drawing.add(canvas);

        clear.addActionListener(this);
        //canvas.add(draw);
        //canvas.addMouseMotionListener(this);

        canvas.setPreferredSize(new Dimension(200, 200));
        canvas.setBackground(Color.green);

        add(drawing);
        add(buttons);
        add(moz);
        add(draw);
        setPreferredSize(new Dimension(1000, 1000));

        setSize(1000, 1000);
        setLayout(gL);
    }

    public void actionPerformed(ActionEvent e) 
    {
         if(e.getSource()==clear)
        {
            //setOpaque(false);
            repaint();
        }
    }

}
class draw extends JFrame implements MouseListener, MouseMotionListener, ActionListener {

    int xPressed,yPressed;
    int xReleased,yReleased;
    int xDragged,yDragged;
    private JButton clear;
    public draw()
    {
        setPreferredSize(new Dimension(1200, 500));
        setBounds(0, 0, 480, 500);
        clear=new JButton("CLEAR");
        add(clear);
        clear.setBounds(540, 5, 100, 25);
        clear.addActionListener(this);
        addMouseListener(this);
        addMouseMotionListener(this);
    }        

    protected void paintComponent(Graphics g)
    {
        g.drawLine(xPressed,yPressed,xDragged,yDragged);
        xPressed=xDragged;
        yPressed=yDragged;
    }

    @Override
    public void mouseDragged(MouseEvent arg0) {
        Graphics g = getGraphics();
        g.drawLine(xPressed, yPressed, arg0.getX(), arg0.getY());
        xDragged = arg0.getX();
        yDragged = arg0.getY();
        repaint();
    }

    @Override
    public void mouseMoved(MouseEvent arg0) {
    }
    @Override
    public void mouseClicked(MouseEvent arg0) {
    }
    @Override
    public void mouseEntered(MouseEvent arg0) {
    }
    @Override
    public void mouseExited(MouseEvent arg0) {
    }
    @Override
    public void mousePressed(MouseEvent arg0) {
        xPressed = arg0.getX();
        yPressed = arg0.getY();
    }
    @Override
    public void mouseReleased(MouseEvent arg0) {
    }

    @Override
    public void actionPerformed(ActionEvent e) {
    }

}    
所以我的想法是创建两个类,一个用来画画,另一个用来创建画画的地方和其他所有东西。我已经尝试了很多东西,但现在我在这里,不知道如何在我的画布上校准draw类,以便它只在那里绘制。之前,我把所有东西都放在一个类中,并在画布上调用鼠标事件。结果是,它只在我点击画布时才绘制,但如果我不放开鼠标并将其从画布中拖出,实际的绘图也会从画布中消失。它也没有在画布上绘制,但在applet的背景上,至少看起来是这样


我真的希望我解释了我的自我理解,并且我确信,这可以很容易地解决,因为在线上有很多解决方案,但我似乎找不到一个能按照我的意愿工作的解决方案。

我建议以
缓冲图像
作为绘画表面,从这个方法开始

import java.awt.*;
import java.awt.RenderingHints.Key;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;

public class BasicPaint {

    /** Reference to the original image. */
    private BufferedImage originalImage;
    /** Image used to make changes. */
    private BufferedImage canvasImage;
    /** The main GUI that might be added to a frame or applet. */
    private JPanel gui;
    /** The color to use when calling clear, text or other 
     * drawing functionality. */
    private Color color = Color.WHITE;
    /** General user messages. */
    private JLabel output = new JLabel("You DooDoodle!");

    private BufferedImage colorSample = new BufferedImage(
            16,16,BufferedImage.TYPE_INT_RGB);
    private JLabel imageLabel;
    private int activeTool;
    public static final int SELECTION_TOOL = 0;
    public static final int DRAW_TOOL = 1;
    public static final int TEXT_TOOL = 2;

    private Point selectionStart; 
    private Rectangle selection;
    private boolean dirty = false;
    private Stroke stroke = new BasicStroke(
            3,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND,1.7f);
    private RenderingHints renderingHints;

    public JComponent getGui() {
        if (gui==null) {
            Map<Key, Object> hintsMap = new HashMap<RenderingHints.Key,Object>();
            hintsMap.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            hintsMap.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            hintsMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            renderingHints = new RenderingHints(hintsMap); 

            setImage(new BufferedImage(320,240,BufferedImage.TYPE_INT_RGB));
            gui = new JPanel(new BorderLayout(4,4));
            gui.setBorder(new EmptyBorder(5,3,5,3));

            JPanel imageView = new JPanel(new GridBagLayout());
            imageView.setPreferredSize(new Dimension(480,320));
            imageLabel = new JLabel(new ImageIcon(canvasImage));
            JScrollPane imageScroll = new JScrollPane(imageView);
            imageView.add(imageLabel);
            imageLabel.addMouseMotionListener(new ImageMouseMotionListener());
            imageLabel.addMouseListener(new ImageMouseListener());
            gui.add(imageScroll,BorderLayout.CENTER);

            JToolBar tb = new JToolBar();
            tb.setFloatable(false);
            JButton colorButton = new JButton("Color");
            colorButton.setMnemonic('o');
            colorButton.setToolTipText("Choose a Color");
            ActionListener colorListener = new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    Color c = JColorChooser.showDialog(
                            gui, "Choose a color", color);
                    if (c!=null) {
                        setColor(c);
                    }
                }
            };
            colorButton.addActionListener(colorListener);
            colorButton.setIcon(new ImageIcon(colorSample));
            tb.add(colorButton);

            setColor(color);

            final SpinnerNumberModel strokeModel = 
                    new SpinnerNumberModel(3,1,16,1);
            JSpinner strokeSize = new JSpinner(strokeModel);
            ChangeListener strokeListener = new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent arg0) {
                    Object o = strokeModel.getValue();
                    Integer i = (Integer)o; 
                    stroke = new BasicStroke(
                            i.intValue(),
                            BasicStroke.CAP_ROUND,
                            BasicStroke.JOIN_ROUND,
                            1.7f);
                }
            };
            strokeSize.addChangeListener(strokeListener);
            strokeSize.setMaximumSize(strokeSize.getPreferredSize());
            JLabel strokeLabel = new JLabel("Stroke");
            strokeLabel.setLabelFor(strokeSize);
            strokeLabel.setDisplayedMnemonic('t');
            tb.add(strokeLabel);
            tb.add(strokeSize);

            tb.addSeparator();

            ActionListener clearListener = new ActionListener() {
                public void actionPerformed(ActionEvent arg0) {
                    int result = JOptionPane.OK_OPTION;
                    if (dirty) {
                        result = JOptionPane.showConfirmDialog(
                                gui, "Erase the current painting?");
                    }
                    if (result==JOptionPane.OK_OPTION) {
                        clear(canvasImage);
                    }
                }
            };
            JButton clearButton = new JButton("Clear");
            tb.add(clearButton);
            clearButton.addActionListener(clearListener);

            gui.add(tb, BorderLayout.PAGE_START);

            JToolBar tools = new JToolBar(JToolBar.VERTICAL);
            tools.setFloatable(false);
            JButton crop = new JButton("Crop");
            final JRadioButton select = new JRadioButton("Select", true);
            final JRadioButton draw = new JRadioButton("Draw");
            final JRadioButton text = new JRadioButton("Text");

            tools.add(crop);            
            tools.add(select);          
            tools.add(draw);            
            tools.add(text);

            ButtonGroup bg = new ButtonGroup();
            bg.add(select);
            bg.add(text);
            bg.add(draw);
            ActionListener toolGroupListener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    if (ae.getSource()==select) {
                        activeTool = SELECTION_TOOL;
                    } else if (ae.getSource()==draw) {
                        activeTool = DRAW_TOOL;
                    } else if (ae.getSource()==text) {
                        activeTool = TEXT_TOOL;
                    }
                }
            };
            select.addActionListener(toolGroupListener);
            draw.addActionListener(toolGroupListener);
            text.addActionListener(toolGroupListener);

            gui.add(tools, BorderLayout.LINE_END);

            gui.add(output,BorderLayout.PAGE_END);
            clear(colorSample);
            clear(canvasImage);
        }

        return gui;
    }

    /** Clears the entire image area by painting it with the current color. */
    public void clear(BufferedImage bi) {
        Graphics2D g = bi.createGraphics();
        g.setRenderingHints(renderingHints);
        g.setColor(color);
        g.fillRect(0, 0, bi.getWidth(), bi.getHeight());

        g.dispose();
        imageLabel.repaint();
    }

    public void setImage(BufferedImage image) {
        this.originalImage = image;
        int w = image.getWidth();
        int h = image.getHeight();
        canvasImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);

        Graphics2D g = this.canvasImage.createGraphics();
        g.setRenderingHints(renderingHints);
        g.drawImage(image, 0, 0, gui);
        g.dispose();

        selection = new Rectangle(0,0,w,h); 
        if (this.imageLabel!=null) {
            imageLabel.setIcon(new ImageIcon(canvasImage));
            this.imageLabel.repaint();
        }
        if (gui!=null) {
            gui.invalidate();
        }
    }

    /** Set the current painting color and refresh any elements needed. */
    public void setColor(Color color) {
        this.color = color;
        clear(colorSample);
    }

    private JMenu getFileMenu(boolean webstart){
        JMenu file = new JMenu("File");
        file.setMnemonic('f');

        JMenuItem newImageItem = new JMenuItem("New");
        newImageItem.setMnemonic('n');
        ActionListener newImage = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                BufferedImage bi = new BufferedImage(
                        360, 300, BufferedImage.TYPE_INT_ARGB);
                clear(bi);
                setImage(bi);
            }
        };
        newImageItem.addActionListener(newImage);
        file.add(newImageItem);

        if (webstart) {
            //TODO Add open/save functionality using JNLP API
        } else {
            //TODO Add save functionality using J2SE API
            file.addSeparator();
            ActionListener openListener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    if (!dirty) {
                        JFileChooser ch = getFileChooser();
                        int result = ch.showOpenDialog(gui);
                        if (result==JFileChooser.APPROVE_OPTION ) {
                            try {
                                BufferedImage bi = ImageIO.read(
                                        ch.getSelectedFile());
                                setImage(bi);
                            } catch (IOException e) {
                                showError(e);
                                e.printStackTrace();
                            }
                        }
                    } else {
                        // TODO
                        JOptionPane.showMessageDialog(
                                gui, "TODO - prompt save image..");
                    }
                }
            };
            JMenuItem openItem = new JMenuItem("Open");
            openItem.setMnemonic('o');
            openItem.addActionListener(openListener);
            file.add(openItem);

            ActionListener saveListener = new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    JFileChooser ch = getFileChooser();
                    int result = ch.showSaveDialog(gui);
                    if (result==JFileChooser.APPROVE_OPTION ) {
                        try {
                            File f = ch.getSelectedFile();
                            ImageIO.write(BasicPaint.this.canvasImage, "png", f);
                            BasicPaint.this.originalImage = BasicPaint.this.canvasImage;
                            dirty = false;
                        } catch (IOException ioe) {
                            showError(ioe);
                            ioe.printStackTrace();
                        }
                    }
                }
            };
            JMenuItem saveItem = new JMenuItem("Save");
            saveItem.addActionListener(saveListener);
            saveItem.setMnemonic('s');
            file.add(saveItem);
        }

        if (canExit()) {
            ActionListener exit = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    System.exit(0);
                }
            };
            JMenuItem exitItem = new JMenuItem("Exit");
            exitItem.setMnemonic('x');
            file.addSeparator();
            exitItem.addActionListener(exit);
            file.add(exitItem);
        }

        return file;
    }

    private void showError(Throwable t) {
        JOptionPane.showMessageDialog(
                gui, 
                t.getMessage(), 
                t.toString(), 
                JOptionPane.ERROR_MESSAGE);
    }

    JFileChooser chooser = null;

    public JFileChooser getFileChooser() {
        if (chooser==null) {
            chooser = new JFileChooser();
            FileFilter ff = new FileNameExtensionFilter("Image files", ImageIO.getReaderFileSuffixes());
            chooser.setFileFilter(ff);
        }
        return chooser;

    }

    public boolean canExit() {
        boolean canExit = false;
        SecurityManager sm = System.getSecurityManager();
        if (sm==null) {
            canExit = true;
        } else {
            try {
                sm.checkExit(0);
                canExit = true; 
            } catch(Exception stayFalse) {
            }
        }

        return canExit;
    }

    public JMenuBar getMenuBar(boolean webstart){
        JMenuBar mb = new JMenuBar();
        mb.add(this.getFileMenu(webstart));
        return mb;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(
                            UIManager.getSystemLookAndFeelClassName());
                } catch (Exception e) {
                    // use default
                }
                BasicPaint bp = new BasicPaint();

                JFrame f = new JFrame("DooDoodle!");
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setLocationByPlatform(true);

                f.setContentPane(bp.getGui());
                f.setJMenuBar(bp.getMenuBar(false));

                f.pack();
                f.setMinimumSize(f.getSize());
                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }

    public void text(Point point) {
        String text = JOptionPane.showInputDialog(gui, "Text to add", "Text");
        if (text!=null) {
            Graphics2D g = this.canvasImage.createGraphics();
            g.setRenderingHints(renderingHints);
            g.setColor(this.color);
            g.setStroke(stroke);
            int n = 0;
            g.drawString(text,point.x,point.y);
            g.dispose();
            this.imageLabel.repaint();
        }
    }

    public void draw(Point point) {
        Graphics2D g = this.canvasImage.createGraphics();
        g.setRenderingHints(renderingHints);
        g.setColor(this.color);
        g.setStroke(stroke);
        int n = 0;
        g.drawLine(point.x, point.y, point.x+n, point.y+n);
        g.dispose();
        this.imageLabel.repaint();
    }

    class ImageMouseListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent arg0) {
            // TODO Auto-generated method stub
            if (activeTool==BasicPaint.SELECTION_TOOL) {
                selectionStart = arg0.getPoint();
            } else if (activeTool==BasicPaint.DRAW_TOOL) {
                // TODO
                draw(arg0.getPoint());
            } else if (activeTool==BasicPaint.TEXT_TOOL) {
                // TODO
                text(arg0.getPoint());
            } else {
                JOptionPane.showMessageDialog(
                        gui, 
                        "Application error.  :(", 
                        "Error!", 
                        JOptionPane.ERROR_MESSAGE);
            }
        }

        @Override
        public void mouseReleased(MouseEvent arg0) {
            if (activeTool==BasicPaint.SELECTION_TOOL) {
                selection = new Rectangle(
                        selectionStart.x,
                        selectionStart.y,
                        arg0.getPoint().x,
                        arg0.getPoint().y);
            }
        }
    }

    class ImageMouseMotionListener implements MouseMotionListener {

        @Override
        public void mouseDragged(MouseEvent arg0) {
            reportPositionAndColor(arg0);
            if (activeTool==BasicPaint.SELECTION_TOOL) {
                selection = new Rectangle(
                        selectionStart.x,
                        selectionStart.y,
                        arg0.getPoint().x-selectionStart.x,
                        arg0.getPoint().y-selectionStart.y);
            } else if (activeTool==BasicPaint.DRAW_TOOL) {
                draw(arg0.getPoint());
            }
        }

        @Override
        public void mouseMoved(MouseEvent arg0) {
            reportPositionAndColor(arg0);
        }

    }

    private void reportPositionAndColor(MouseEvent me) {
        String text = "";
        if (activeTool==BasicPaint.SELECTION_TOOL) {
            text += "Selection (X,Y:WxH): " + 
                    (int)selection.getX() +
                    "," +
                    (int)selection.getY() +
                    ":" +
                    (int)selection.getWidth() +
                    "x" +
                    (int)selection.getHeight();
        } else {
            text += "X,Y: " + (me.getPoint().x+1) + "," + (me.getPoint().y+1);
        }
        output.setText(text);
    }
}

import java.awt.*;
导入java.awt.RenderingHints.Key;
导入java.awt.event.*;
导入java.awt.image.buffereImage;
导入java.io.File;
导入java.io.IOException;
导入java.util.HashMap;
导入java.util.Map;
导入javax.imageio.imageio;
导入javax.swing.*;
导入javax.swing.border.*;
导入javax.swing.event.ChangeEvent;
导入javax.swing.event.ChangeListener;
导入javax.swing.filechooser.FileFilter;
导入javax.swing.filechooser.FileNameExtensionFilter;
公共类基本点{
/**参考原始图像*/
私有缓冲区图像原始图像;
/**用于进行更改的图像*/
私有缓冲区图像画布图像;
/**可能添加到框架或小程序的主GUI*/
私有JPanel gui;
/**调用clear、text或其他时要使用的颜色
*绘图功能*/
私有颜色=Color.WHITE;
/**一般用户消息*/
私有JLabel输出=新JLabel(“你乱画!”);
private BuffereImage colorSample=新BuffereImage(
16,16,BuffereImage.TYPE_INT_RGB);
专用JLabel图像标签;
私有int-activeTool;
公共静态最终整数选择工具=0;
公共静态最终整数绘制工具=1;
公共静态最终整型文本工具=2;
私人点选择启动;
私有矩形选择;
私有布尔脏=假;
私人行程行程=新的基本行程(
3,基本行程。CAP_ROUND,基本行程。JOIN_ROUND,1.7f);
私有渲染提示渲染提示;
公共JComponent getGui(){
if(gui==null){
Map hintsMap=newhashmap();
hintsMap.put(RenderingHints.KEY\u RENDERING,RenderingHints.VALUE\u RENDER\u QUALITY);
hintsMap.put(renderinghits.KEY\u抖动,renderinghits.VALUE\u抖动\u启用);
hintsMap.put(renderinghits.KEY\u TEXT\u抗锯齿,renderinghits.VALUE\u TEXT\u antialas\u ON);
renderingHints=新的renderingHints(hintsMap);
setImage(新的BufferedImage(320240,BufferedImage.TYPE_INT_RGB));
gui=新JPanel(新边界布局(4,4));
新订单(新的空订单(5,3,5,3));
JPanel imageView=新的JPanel(新的GridBagLayout());
setPreferredSize(新维度(480320));
imageLabel=new JLabel(new ImageIcon(canvasImage));
JScrollPane imageScroll=新的JScrollPane(imageView);
添加(imageLabel);
addMouseMotionListener(新的ImageMouseMotionListener());
addMouseListener(新的ImageMouseListener());
添加(imageScroll,BorderLayout.CENTER);
JToolBar tb=新的JToolBar();
tb.可设置浮动(假);
JButton colorButton=新JButton(“颜色”);
colorButton.set助记符('o');
setToolTiptText(“选择颜色”);
ActionListener colorListener=新建ActionListener(){
已执行的公共无效操作(操作事件arg0){
颜色c=JColorChooser.showDialog(
gui,“选择颜色”,颜色);
如果(c!=null){
setColor(c);
}
}
};
addActionListener(colorListener);
colorButton.setIcon(新图像图标(colorSample));
tb.add(彩色按钮);
设置颜色(颜色);
最终喷丝头编号模型冲程模型=
新喷丝头型号(3,1,16,1);
JSpinner-strokeSize=新的JSpinner(strokeModel);
ChangeListener StrokListener=新的ChangeListener(){
@凌驾
公共无效状态已更改(ChangeEvent arg0){
对象o=strokeModel.getValue();
整数i=(整数)o;
冲程=新的基本冲程(
i、 intValue(),
BasicStroke.CAP_ROUND,
基本行程,
1.7f);
}
};
addChangeListener(strokListener);
strokeSize.setMaximumSize(strokeSize.getPreferredSize());
JLabel strokeLabel=新JLabel(“行程”);
strokeLabel.setLabelFor(strokeSize);
strokeLabel.setdisplayednemonic('t');
tb.add(strokeLabel);