0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【JavaSwing】お絵描きツールの作り方

Posted at

chatGPTにJavaでのお絵描きツールの作り方を聞いてEclipseで作ってみたので、勉強のやる気を出すためにもメモ。

ArtCanvas.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

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

public class ArtCanvas extends JFrame {

    private DrawArea drawArea;

    public ArtCanvas() {
        setTitle("描いて遊べるアートキャンバス 🎨");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);

        drawArea = new DrawArea();
        add(drawArea, BorderLayout.CENTER);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ArtCanvas::new);
    }
}

class DrawArea extends JPanel {

    private List<Line> lines = new ArrayList<>();
    private int prevX, prevY;
    private boolean drawing = false;

    public DrawArea() {
        setBackground(Color.WHITE);

        // マウスの動きとクリックを検知
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                prevX = e.getX();
                prevY = e.getY();
                drawing = true;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                drawing = false;
            }
        });

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (drawing) {
                    int x = e.getX();
                    int y = e.getY();
                    lines.add(new Line(prevX, prevY, x, y));
                    prevX = x;
                    prevY = y;
                    repaint(); // 再描画
                }
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 描いた線を全部描画
        g.setColor(Color.BLACK);
        for (Line line : lines) {
            g.drawLine(line.x1, line.y1, line.x2, line.y2);
        }
    }

    private static class Line {
        int x1, y1, x2, y2;

        Line(int x1, int y1, int x2, int y2) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
        }
    }
}

  
実行すると、以下のようなウインドウが表示される。
image.png

  
マウスで黒い線を描ける。
image.png

  
色を選べるようにした。

ArtCanvas.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

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

public class ArtCanvas extends JFrame {

    private DrawArea drawArea;

    public ArtCanvas() {
        setTitle("描いて遊べるアートキャンバス 🎨");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);

        drawArea = new DrawArea();
        add(drawArea, BorderLayout.CENTER);
        
        // 🎨 カラーパネルを作る
        JPanel colorPanel = new JPanel();
        colorPanel.setLayout(new FlowLayout());

        // いくつかの色ボタンを追加
        Color[] colors = {Color.BLACK, Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.MAGENTA};
        for (Color c : colors) {
            JButton btn = new JButton();
            btn.setBackground(c);
            btn.setPreferredSize(new Dimension(20, 20));
            btn.addActionListener(e -> drawArea.setCurrentColor(c));
            colorPanel.add(btn);
        }

        // 「カラーピッカー」ボタン(自由に色を選ぶ)
        JButton pickerBtn = new JButton("その他の色...");
        pickerBtn.addActionListener(e -> {
            Color newColor = JColorChooser.showDialog(this, "色を選択", drawArea.getCurrentColor());
            if (newColor != null) {
                drawArea.setCurrentColor(newColor);
            }
        });
        colorPanel.add(pickerBtn);

        add(colorPanel, BorderLayout.NORTH);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ArtCanvas::new);
    }
}

class DrawArea extends JPanel {

    private List<Line> lines = new ArrayList<>();
    private int prevX, prevY;
    private boolean drawing = false;
    private Color currentColor = Color.BLACK;

    public DrawArea() {
        setBackground(Color.WHITE);

        // マウスの動きとクリックを検知
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                prevX = e.getX();
                prevY = e.getY();
                drawing = true;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                drawing = false;
            }
        });

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (drawing) {
                    int x = e.getX();
                    int y = e.getY();
                    lines.add(new Line(prevX, prevY, x, y, currentColor));
                    prevX = x;
                    prevY = y;
                    repaint(); // 再描画
                }
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 描いた線を全部描画
        for (Line line : lines) {
        	g.setColor(line.color);
            g.drawLine(line.x1, line.y1, line.x2, line.y2);
        }
    }
    
    public void setCurrentColor(Color c) {
    	this.currentColor = c;
    }
    
    public Color getCurrentColor() {
    	return this.currentColor;
    }
    
    private static class Line {
        int x1, y1, x2, y2;
        Color color;

        Line(int x1, int y1, int x2, int y2, Color color) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.color = color;
        }
    }
}

  
実行すると、以下のとおり。
image.png

  
描いてみると…
image.png

  
「その他の色」ボタンを押下すると、以下のようなカラーパレットがある。
image.png

image.png

image.png

image.png

image.png

  
カラーパレットで選択した色で描いてみた。
image.png

  
次は、消しゴムを追加してみた。
ChatGPTによると「白い線は実質消しゴム!」とのこと。背景が白の場合はそれでいいのかも。

ArtCanvas.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

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

public class ArtCanvas extends JFrame {

    private DrawArea drawArea;
    private Color lastSelectedColor = Color.BLACK; // ← 直前の色を覚えておく

    public ArtCanvas() {
        setTitle("描いて遊べるアートキャンバス 🎨");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);

        drawArea = new DrawArea();
        add(drawArea, BorderLayout.CENTER);
        
        // 🎨 カラーパネル
        JPanel colorPanel = new JPanel();
        colorPanel.setLayout(new FlowLayout());

        // 色ボタン
        Color[] colors = {Color.BLACK, Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.MAGENTA};
        for (Color c : colors) {
            JButton btn = new JButton();
            btn.setBackground(c);
            btn.setPreferredSize(new Dimension(20, 20));
            btn.addActionListener(e -> drawArea.setCurrentColor(c));
            colorPanel.add(btn);
        }

        // 「カラーピッカー」ボタン(自由に色を選ぶ)
        JButton pickerBtn = new JButton("その他の色...");
        pickerBtn.addActionListener(e -> {
            Color newColor = JColorChooser.showDialog(this, "色を選択", drawArea.getCurrentColor());
            if (newColor != null) {
                drawArea.setCurrentColor(newColor);
            }
        });
        colorPanel.add(pickerBtn);
        
        // 🧼 消しゴムボタン
        JButton eraserBtn = new JButton("🧽 消しゴム");
        eraserBtn.addActionListener(e -> drawArea.setCurrentColor(Color.WHITE));
        colorPanel.add(eraserBtn);
        
        // 🖌 ペンに戻るボタン
        JButton penBtn = new JButton("✏️ ペンに戻る");
        penBtn.addActionListener(e -> drawArea.setCurrentColor(lastSelectedColor));
        colorPanel.add(penBtn);

        add(colorPanel, BorderLayout.NORTH);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ArtCanvas::new);
    }
}

class DrawArea extends JPanel {

    private List<Line> lines = new ArrayList<>();
    private int prevX, prevY;
    private boolean drawing = false;
    private Color currentColor = Color.BLACK;

    public DrawArea() {
        setBackground(Color.WHITE);

        // マウスの動きとクリックを検知
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                prevX = e.getX();
                prevY = e.getY();
                drawing = true;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                drawing = false;
            }
        });

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (drawing) {
                    int x = e.getX();
                    int y = e.getY();
                    lines.add(new Line(prevX, prevY, x, y, currentColor));
                    prevX = x;
                    prevY = y;
                    repaint(); // 再描画
                }
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 描いた線を全部描画
        for (Line line : lines) {
        	g.setColor(line.color);
            g.drawLine(line.x1, line.y1, line.x2, line.y2);
        }
    }
    
    public void setCurrentColor(Color c) {
    	this.currentColor = c;
    }
    
    public Color getCurrentColor() {
    	return this.currentColor;
    }
    
    private static class Line {
        int x1, y1, x2, y2;
        Color color;

        Line(int x1, int y1, int x2, int y2, Color color) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.color = color;
        }
    }
}

  
こんな感じになった。
image.png

  
「ペンに戻る」ボタンを押下すると黒いペンに。
image.png

  
線の太さを変えられるようにしてみた。

ArtCanvas.java
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;

public class ArtCanvas extends JFrame {

    private DrawArea drawArea;
    private Color lastSelectedColor = Color.BLACK; // ← 直前の色を覚えておく

    public ArtCanvas() {
        setTitle("描いて遊べるアートキャンバス 🎨");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);

        drawArea = new DrawArea();
        add(drawArea, BorderLayout.CENTER);
        
        // 🎨 カラーパネル
        JPanel colorPanel = new JPanel();
        colorPanel.setLayout(new FlowLayout());

        // 色ボタン
        Color[] colors = {Color.BLACK, Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.MAGENTA};
        for (Color c : colors) {
            JButton btn = new JButton();
            btn.setBackground(c);
            btn.setPreferredSize(new Dimension(20, 20));
            btn.addActionListener(e -> {
            lastSelectedColor = c;	
            drawArea.setCurrentColor(c);
        });
            colorPanel.add(btn);
        }

        // 「カラーピッカー」ボタン(自由に色を選ぶ)
        JButton pickerBtn = new JButton("その他の色...");
        pickerBtn.addActionListener(e -> {
            Color newColor = JColorChooser.showDialog(this, "色を選択", drawArea.getCurrentColor());
            if (newColor != null) {
                drawArea.setCurrentColor(newColor);
            }
        });
        colorPanel.add(pickerBtn);
        
        // 🧼 消しゴムボタン
        JButton eraserBtn = new JButton("🧽 消しゴム");
        eraserBtn.addActionListener(e -> drawArea.setCurrentColor(Color.WHITE));
        colorPanel.add(eraserBtn);
        
        // 🖌 ペンに戻るボタン
        JButton penBtn = new JButton("✏️ ペンに戻る");
        penBtn.addActionListener(e -> drawArea.setCurrentColor(lastSelectedColor));
        colorPanel.add(penBtn);

        add(colorPanel, BorderLayout.NORTH);
        
        // ✨ 線の太さスライダー
        JPanel bottomPanel = new JPanel();
        JLabel sliderLabel = new JLabel("線の太さ:");
        JSlider thicknessSlider = new JSlider(1, 50, 5); // 最小1, 最大50, 初期値5
        thicknessSlider.setMajorTickSpacing(5);
        thicknessSlider.setPaintTicks(true);
        thicknessSlider.setPaintLabels(true);

        thicknessSlider.addChangeListener(e -> {
            int value = thicknessSlider.getValue();
            drawArea.setCurrentThickness(value);
        });

        bottomPanel.add(sliderLabel);
        bottomPanel.add(thicknessSlider);

        add(bottomPanel, BorderLayout.SOUTH);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ArtCanvas::new);
    }
}

class DrawArea extends JPanel {

    private List<Line> lines = new ArrayList<>();
    private int prevX, prevY;
    private boolean drawing = false;
    private Color currentColor = Color.BLACK;
    private float currentThickness = 3f;

    public DrawArea() {
        setBackground(Color.WHITE);

        // マウスの動きとクリックを検知
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                prevX = e.getX();
                prevY = e.getY();
                drawing = true;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                drawing = false;
            }
        });

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (drawing) {
                    int x = e.getX();
                    int y = e.getY();
                    lines.add(new Line(prevX, prevY, x, y, currentColor, currentThickness));
                    prevX = x;
                    prevY = y;
                    repaint(); // 再描画
                }
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        // 描いた線を全部描画
        for (Line line : lines) {
        	g.setColor(line.color);
        	g2.setStroke(new BasicStroke(line.thickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            g.drawLine(line.x1, line.y1, line.x2, line.y2);
        }
    }
    
    public void setCurrentColor(Color c) {
    	this.currentColor = c;
    }
    
    public Color getCurrentColor() {
    	return this.currentColor;
    }
    
    public void setCurrentThickness(float thickness) {
    	this.currentThickness = thickness;
    }
    
    private static class Line {
        int x1, y1, x2, y2;
        Color color;
        float thickness;

        Line(int x1, int y1, int x2, int y2, Color color, float thickness) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.color = color;
            this.thickness = thickness;
        }
    }
}

  
いろんな太さの線で描いてみた。
image.png

 
画像保存できるようにしてみた。

ArtCanvas.java
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;

public class ArtCanvas extends JFrame {

    private DrawArea drawArea;
    private Color lastSelectedColor = Color.BLACK; // ← 直前の色を覚えておく

    public ArtCanvas() {
        setTitle("描いて遊べるアートキャンバス 🎨");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);

        drawArea = new DrawArea();
        add(drawArea, BorderLayout.CENTER);
        
        // 🎨 カラーパネル
        JPanel colorPanel = new JPanel();
        colorPanel.setLayout(new FlowLayout());

        // 色ボタン
        Color[] colors = {Color.BLACK, Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.MAGENTA};
        for (Color c : colors) {
            JButton btn = new JButton();
            btn.setBackground(c);
            btn.setPreferredSize(new Dimension(20, 20));
            btn.addActionListener(e -> {
            lastSelectedColor = c;	
            drawArea.setCurrentColor(c);
        });
            colorPanel.add(btn);
        }

        // 「カラーピッカー」ボタン(自由に色を選ぶ)
        JButton pickerBtn = new JButton("その他の色...");
        pickerBtn.addActionListener(e -> {
            Color newColor = JColorChooser.showDialog(this, "色を選択", drawArea.getCurrentColor());
            if (newColor != null) {
            	lastSelectedColor = newColor;
                drawArea.setCurrentColor(newColor);
            }
        }); 
        colorPanel.add(pickerBtn);
        
        // 🧼 消しゴムボタン
        JButton eraserBtn = new JButton("🧽 消しゴム");
        eraserBtn.addActionListener(e -> drawArea.setCurrentColor(Color.WHITE));
        colorPanel.add(eraserBtn);
        
        // 🖌 ペンに戻るボタン
        JButton penBtn = new JButton("✏️ ペンに戻る");
        penBtn.addActionListener(e -> drawArea.setCurrentColor(lastSelectedColor));
        colorPanel.add(penBtn);
        
        // 💾 画像保存ボタン
        JButton saveBtn = new JButton("💾 画像を保存");
        saveBtn.addActionListener(e -> drawArea.saveImage());
        colorPanel.add(saveBtn);

        add(colorPanel, BorderLayout.NORTH);
        
        // ✨ 線の太さスライダー
        JPanel bottomPanel = new JPanel();
        JLabel sliderLabel = new JLabel("線の太さ:");
        JSlider thicknessSlider = new JSlider(1, 50, 5); // 最小1, 最大50, 初期値5
        thicknessSlider.setMajorTickSpacing(5);
        thicknessSlider.setPaintTicks(true);
        thicknessSlider.setPaintLabels(true);

        thicknessSlider.addChangeListener(e -> {
            int value = thicknessSlider.getValue();
            drawArea.setCurrentThickness(value);
        });

        bottomPanel.add(sliderLabel);
        bottomPanel.add(thicknessSlider);
        add(bottomPanel, BorderLayout.SOUTH);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ArtCanvas::new);
    }
}

class DrawArea extends JPanel {

    private List<Line> lines = new ArrayList<>();
    private int prevX, prevY;
    private boolean drawing = false;
    private Color currentColor = Color.BLACK;
    private float currentThickness = 3f;

    public DrawArea() {
        setBackground(Color.WHITE);

        // マウスの動きとクリックを検知
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                prevX = e.getX();
                prevY = e.getY();
                drawing = true;
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                drawing = false;
            }
        });

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (drawing) {
                    int x = e.getX();
                    int y = e.getY();
                    lines.add(new Line(prevX, prevY, x, y, currentColor, currentThickness));
                    prevX = x;
                    prevY = y;
                    repaint(); // 再描画
                }
            }
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        // 描いた線を全部描画
        for (Line line : lines) {
        	g.setColor(line.color);
        	g2.setStroke(new BasicStroke(line.thickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            g.drawLine(line.x1, line.y1, line.x2, line.y2);
        }
    }
    
    public void setCurrentColor(Color c) {
    	this.currentColor = c;
    }
    
    public Color getCurrentColor() {
    	return this.currentColor;
    }
    
    public void setCurrentThickness(float thickness) {
    	this.currentThickness = thickness;
    }
    
    // 💾 画像保存
    public void saveImage() {
        // 描画内容を BufferedImage に書き出す
        BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = image.createGraphics();
        paint(g2);
        g2.dispose();

        // 保存ダイアログ
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("画像を保存");
        fileChooser.setSelectedFile(new File("my_drawing.png"));
        int userSelection = fileChooser.showSaveDialog(this);

        if (userSelection == JFileChooser.APPROVE_OPTION) {
            File fileToSave = fileChooser.getSelectedFile();
            try {
                // 拡張子がない場合、自動で .png をつける
                String path = fileToSave.getAbsolutePath();
                if (!path.toLowerCase().endsWith(".png")) {
                    fileToSave = new File(path + ".png");
                }
                ImageIO.write(image, "png", fileToSave);
                JOptionPane.showMessageDialog(this, "画像を保存しました!\n" + fileToSave.getAbsolutePath());
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(this, "保存に失敗しました: " + ex.getMessage());
            }
        }
    }
    
    private static class Line {
        int x1, y1, x2, y2;
        Color color;
        float thickness;

        Line(int x1, int y1, int x2, int y2, Color color, float thickness) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.color = color;
            this.thickness = thickness;
        }
    }
}

  
image.png

  
保存できた! やった~。
image.png

  
塗りつぶしや画面の描画の全削除等も入れて、不要な部分を削除したりした。

ArtCanvas.java
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.LinkedList;
import java.util.Queue;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;

public class ArtCanvas extends JFrame {

    private DrawArea drawArea;

    public ArtCanvas() {
        setTitle("描いて遊べるアートキャンバス 🎨");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(800, 600);

        drawArea = new DrawArea();
        add(drawArea, BorderLayout.CENTER);
        
        // 🎨 カラーパネル
        JPanel colorPanel = new JPanel();
        colorPanel.setLayout(new FlowLayout());

        // 色ボタン
        Color[] colors = {Color.BLACK, Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.MAGENTA};
        for (Color c : colors) {
            JButton btn = new JButton();
            btn.setBackground(c);
            btn.setPreferredSize(new Dimension(20, 20));
            btn.addActionListener(e -> {
            drawArea.setCurrentColor(c);
        });
            colorPanel.add(btn);
        }

        // 「カラーピッカー」ボタン(自由に色を選ぶ)
        JButton pickerBtn = new JButton("その他の色...");
        pickerBtn.addActionListener(e -> {
            Color newColor = JColorChooser.showDialog(this, "色を選択", drawArea.getCurrentColor());
            if (newColor != null) {
                drawArea.setCurrentColor(newColor);
            }
        }); 
        colorPanel.add(pickerBtn);
        
        // 🖌 ペンボタン
        JButton penBtn = new JButton("ペン");
        penBtn.addActionListener(e -> drawArea.setTool("pen"));
        colorPanel.add(penBtn);
        
        // 塗りつぶし
        JButton fillBtn = new JButton("塗りつぶし");
        fillBtn.addActionListener(e -> drawArea.setTool("fill"));
        colorPanel.add(fillBtn);
        
        // 🧼 消しゴムボタン
        JButton eraserBtn = new JButton("消しゴム");
        eraserBtn.addActionListener(e -> drawArea.setCurrentColor(Color.WHITE));
        colorPanel.add(eraserBtn);
        
        // 🧭 全削除
        JButton clearBtn = new JButton("全削除");
        clearBtn.addActionListener(e -> drawArea.clearCanvas());
        colorPanel.add(clearBtn);
        
        // 💾 画像保存ボタン
        JButton saveBtn = new JButton("💾 画像を保存");
        saveBtn.addActionListener(e -> drawArea.saveImage());
        colorPanel.add(saveBtn);

        add(colorPanel, BorderLayout.NORTH);
        
        // ✨ 線の太さスライダー
        JPanel bottomPanel = new JPanel();
        JLabel sliderLabel = new JLabel("線の太さ:");
        JSlider thicknessSlider = new JSlider(1, 50, 5); // 最小1, 最大50, 初期値5
        thicknessSlider.setMajorTickSpacing(5);
        thicknessSlider.setPaintTicks(true);
        thicknessSlider.setPaintLabels(true);

        thicknessSlider.addChangeListener(e -> {
            int value = thicknessSlider.getValue();
            drawArea.setCurrentThickness(value);
        });

        bottomPanel.add(sliderLabel);
        bottomPanel.add(thicknessSlider);
        add(bottomPanel, BorderLayout.SOUTH);

        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(ArtCanvas::new);
    }
}

class DrawArea extends JPanel {

    private int prevX, prevY;
    private boolean drawing = false;
    private Color currentColor = Color.BLACK;
    private float currentThickness = 3f;
    private BufferedImage canvas;
    private String currentTool = "pen"; // pen or fill

    public DrawArea() {
        setBackground(Color.WHITE);
        
        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                initCanvas();
            }
        });

        // マウスの動きとクリックを検知
        addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
            	int x = e.getX();
                int y = e.getY();
                
                if (currentTool.equals("pen")) {
                prevX = e.getX();
                prevY = e.getY();
                drawing = true;
                } else if (currentTool.equals("fill")) {
                    floodFill(x, y, canvas.getRGB(x, y), currentColor.getRGB());
                    repaint();
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                drawing = false;
            }
        });

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                if (drawing) {
                    int x = e.getX();
                    int y = e.getY();
                 // これまでlinesに記録していたけど、canvasに直接描いてるので不要になる
                 // lines.add(new Line(prevX, prevY, x, y, currentColor, currentThickness));
                    Graphics2D g2m = canvas.createGraphics(); // canvasに直接描く
                    g2m.setColor(currentColor);
                    g2m.setStroke(new BasicStroke(currentThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
                    g2m.drawLine(prevX, prevY, x, y);
                    g2m.dispose();

                    prevX = x;
                    prevY = y;
                    repaint(); // 再描画
                }
            }
        });
    }
    
    private void initCanvas() {
        int w = getWidth();
        int h = getHeight();
        if (w <= 0 || h <= 0) return;

        BufferedImage newCanvas = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2i = newCanvas.createGraphics();
        g2i.setColor(Color.WHITE);
        g2i.fillRect(0, 0, w, h);
        if (canvas != null) {
        	g2i.drawImage(canvas, 0, 0, null);
        }
        g2i.dispose();
        canvas = newCanvas;
    }

    // 🪣 Flood Fill(非再帰版)
    private void floodFill(int startX, int startY, int targetColor, int replacementColor) {
        if (targetColor == replacementColor) return;
        if (startX < 0 || startY < 0 || startX >= canvas.getWidth() || startY >= canvas.getHeight()) return;
        if (canvas.getRGB(startX, startY) != targetColor) return;

        Queue<Point> queue = new LinkedList<>();
        queue.add(new Point(startX, startY));

        while (!queue.isEmpty()) {
            Point p = queue.poll();
            int x = p.x;
            int y = p.y;

            if (x < 0 || y < 0 || x >= canvas.getWidth() || y >= canvas.getHeight()) continue;
            if (canvas.getRGB(x, y) != targetColor) continue;

            canvas.setRGB(x, y, replacementColor);

            queue.add(new Point(x + 1, y));
            queue.add(new Point(x - 1, y));
            queue.add(new Point(x, y + 1));
            queue.add(new Point(x, y - 1));
        }
    }
    
    // 🧭 全削除
    public void clearCanvas() {
        Graphics2D g2c = canvas.createGraphics();
        g2c.setColor(Color.WHITE);
        g2c.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
        g2c.dispose();
        repaint();
    }
        
    // 💾 画像保存
    public void saveImage() {
        // 描画内容を BufferedImage に書き出す
        BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics2D g2s = image.createGraphics();
        paint(g2s);
        g2s.dispose();

        // 保存ダイアログ
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("画像を保存");
        fileChooser.setSelectedFile(new File("my_drawing.png"));
        int userSelection = fileChooser.showSaveDialog(this);

        if (userSelection == JFileChooser.APPROVE_OPTION) {
            File fileToSave = fileChooser.getSelectedFile();
            try {
                // 拡張子がない場合、自動で .png をつける
                String path = fileToSave.getAbsolutePath();
                if (!path.toLowerCase().endsWith(".png")) {
                    fileToSave = new File(path + ".png");
                }
                ImageIO.write(image, "png", fileToSave);
                JOptionPane.showMessageDialog(this, "画像を保存しました!\n" + fileToSave.getAbsolutePath());
            } catch (Exception ex) {
                JOptionPane.showMessageDialog(this, "保存に失敗しました: " + ex.getMessage());
            }
        }
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
            g.drawImage(canvas, 0, 0, null);
    }
    
    public void setCurrentColor(Color c) {
    	this.currentColor = c;
    }
    
    public Color getCurrentColor() {
    	return this.currentColor;
    }
    
    public void setTool(String tool) {
        this.currentTool = tool;
    }
    
    public void setCurrentThickness(float thickness) {
    	this.currentThickness = thickness;
    }
}

  
嬉しい!
image.png

ちょっとずつ改良したい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?