这是一个简单的 Java 铅笔画图程序。程序不是直接将笔划画到控件上,而是先画到 Image 对象,然后将 Image 对象画到控件上,这样画出来的图不会被抹去。
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.HeadlessException;
import java.awt.RenderingHints;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;/**
 * 简单的 Java 铅笔画图程序。程序不是直接将笔划画到控件上,而是
 * 先画到 Image 对象,然后将 Image 对象画到控件上,这样画出来
 * 的图不会被抹去。
 */
public class JPencil extends JFrame {    // 程序执行入口
    public static void main(String[] args) throws Exception {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();
        }        new JPencil("JPencil").setVisible(true);
    }    public JPencil(String title) throws HeadlessException {
        super(title);
        setupWindow();      // 设置窗体
        setupControls();    // 设置控件
    }    private void setupControls() {
        this.setLayout(new BorderLayout());        final DrawPanel drawPanel = new DrawPanel();
        this.add(drawPanel, BorderLayout.CENTER);        final JPencil frame = this;
        // 当窗口打开的时候初始化 drawPanel(否则无法获取正确的大小)
        this.addHierarchyListener(new HierarchyListener() {            public void hierarchyChanged(HierarchyEvent e) {
                boolean isShowingUp = frame.isVisible() &&
                        e.getChangeFlags() == HierarchyEvent.SHOWING_CHANGED;                if (isShowingUp) {
                    drawPanel.init();
                    frame.removeHierarchyListener(this);  // 只初始化一次
                }
            }
        });
    }    private void setupWindow() {
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setSize(800, 600);
        this.setLocation(50, 50);
    }    /////////////////////////////////////////    /**
     * 绘图板
     */
    private class DrawPanel extends JPanel {        private BufferedImage image;    // 缓存的 Image 对象        // 初始化
        public void init() {
            this.image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);            new Pencil(this, this.image.createGraphics());
        }        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(this.image, 0, 0, null);
        }
    }    /////////////////////////////////////////    /**
     * 铅笔工具
     */
    private class Pencil extends MouseAdapter {        private Graphics2D graphics;        private Component component;        private int lastX = -1, lastY = -1;        /**
         * 构造函数
         *
         * @param component 可绘图的 Component 对象
         * @param graphics  绘图对象
         */
        public Pencil(Component component, Graphics2D graphics) {
            this.graphics = graphics;
            this.component = component;
            this.clear();            component.addMouseListener(this);       // MouseListener 负责处理鼠标键按下和松开事件
            component.addMouseMotionListener(this); // MouseMotionListener 负责处理鼠标拖拽事件
        }        private void clear() {
            Graphics2D graphics = this.graphics;
            graphics.setColor(Color.white);
            graphics.fillRect(0, 0, getWidth(), getHeight());
            graphics.setColor(Color.black);
        }        private void draw(int x, int y) {
            Graphics2D graphics = this.graphics;
            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            graphics.setColor(Color.black);
            
            // 从上次记录的鼠标位置到当前鼠标位置画一条直线。当不停地
            // 获取到鼠标位置时,画出来的就是一条鼠标移动的轨迹了。
            graphics.drawLine(lastX, lastY, x, y);
            
            this.component.repaint();
        }
        
        /////////////////////////////////////////        @Override
        public void mouseDragged(MouseEvent e) {
            if (this.lastX != -1 && this.lastY != -1) {
                draw(e.getX(), e.getY());
            }            this.lastX = e.getX();
            this.lastY = e.getY();
        }        @Override
        public void mousePressed(MouseEvent e) {
            // 设置绘图的起始点
            this.lastX = e.getX();
            this.lastY = e.getY();
        }        @Override
        public void mouseReleased(MouseEvent e) {
            // 结束绘图
            this.lastX = -1;
            this.lastY = -1;
        }
    }
}