import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.Stack;
import javax.imageio.ImageIO;
import java.io.File;
public class AdvancedPaintAppWithUndoRedo extends JFrame {
private DrawPanel drawPanel;
private Color currentColor = Color.BLACK;
private int brushSize = 4;
private String currentTool = "Brush";
private Stack<BufferedImage> undoStack = new Stack<>();
private Stack<BufferedImage> redoStack = new Stack<>();
public AdvancedPaintAppWithUndoRedo() {
setTitle("Advanced Paint Application with Undo/Redo");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
drawPanel = new DrawPanel();
add(drawPanel, BorderLayout.CENTER);
// メニューバーの作成
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
JMenuItem saveItem = new JMenuItem("Save");
JMenuItem openItem = new JMenuItem("Open");
JMenuItem clearItem = new JMenuItem("Clear");
saveItem.addActionListener(e -> saveImage());
openItem.addActionListener(e -> openImage());
clearItem.addActionListener(e -> drawPanel.clearCanvas());
fileMenu.add(saveItem);
fileMenu.add(openItem);
fileMenu.add(clearItem);
menuBar.add(fileMenu);
JMenu toolMenu = new JMenu("Tools");
JMenuItem colorItem = new JMenuItem("Choose Color");
JMenuItem brushItem = new JMenuItem("Brush Size");
JMenuItem toolBrush = new JMenuItem("Brush");
JMenuItem toolLine = new JMenuItem("Line");
JMenuItem toolRect = new JMenuItem("Rectangle");
JMenuItem toolOval = new JMenuItem("Oval");
JMenuItem toolText = new JMenuItem("Text");
colorItem.addActionListener(e -> chooseColor());
brushItem.addActionListener(e -> chooseBrushSize());
toolBrush.addActionListener(e -> currentTool = "Brush");
toolLine.addActionListener(e -> currentTool = "Line");
toolRect.addActionListener(e -> currentTool = "Rectangle");
toolOval.addActionListener(e -> currentTool = "Oval");
toolText.addActionListener(e -> currentTool = "Text");
toolMenu.add(colorItem);
toolMenu.add(brushItem);
toolMenu.add(toolBrush);
toolMenu.add(toolLine);
toolMenu.add(toolRect);
toolMenu.add(toolOval);
toolMenu.add(toolText);
menuBar.add(toolMenu);
JMenu editMenu = new JMenu("Edit");
JMenuItem undoItem = new JMenuItem("Undo");
JMenuItem redoItem = new JMenuItem("Redo");
undoItem.addActionListener(e -> drawPanel.undo());
redoItem.addActionListener(e -> drawPanel.redo());
editMenu.add(undoItem);
editMenu.add(redoItem);
menuBar.add(editMenu);
setJMenuBar(menuBar);
}
// メインメソッド
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
AdvancedPaintAppWithUndoRedo app = new AdvancedPaintAppWithUndoRedo();
app.setVisible(true);
});
}
// 色を選択する
private void chooseColor() {
Color color = JColorChooser.showDialog(null, "Choose a Color", currentColor);
if (color != null) {
currentColor = color;
drawPanel.setColor(color);
}
}
// ブラシサイズを選択する
private void chooseBrushSize() {
String sizeStr = JOptionPane.showInputDialog(this, "Enter brush size:", brushSize);
if (sizeStr != null) {
try {
int size = Integer.parseInt(sizeStr);
if (size > 0) {
brushSize = size;
drawPanel.setBrushSize(size);
}
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "Invalid size entered.");
}
}
}
// 画像を保存する
private void saveImage() {
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
try {
ImageIO.write(drawPanel.getImage(), "png", file);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
// 画像を開く
private void openImage() {
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
try {
BufferedImage image = ImageIO.read(file);
drawPanel.setImage(image);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
// 描画用のパネル
class DrawPanel extends JPanel {
private BufferedImage image;
private Graphics2D g2;
private int startX, startY, endX, endY;
public DrawPanel() {
setPreferredSize(new Dimension(800, 600));
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
if (g2 != null) {
if (currentTool.equals("Brush")) {
g2.fillOval(startX, startY, brushSize, brushSize);
}
saveToUndoStack();
}
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
endX = e.getX();
endY = e.getY();
if (g2 != null) {
switch (currentTool) {
case "Line":
g2.drawLine(startX, startY, endX, endY);
break;
case "Rectangle":
g2.drawRect(Math.min(startX, endX), Math.min(startY, endY),
Math.abs(startX - endX), Math.abs(startY - endY));
break;
case "Oval":
g2.drawOval(Math.min(startX, endX), Math.min(startY, endY),
Math.abs(startX - endX), Math.abs(startY - endY));
break;
case "Text":
String text = JOptionPane.showInputDialog("Enter text:");
if (text != null) {
g2.drawString(text, startX, startY);
}
break;
}
}
saveToUndoStack();
repaint();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
if (currentTool.equals("Brush")) {
g2.fillOval(e.getX(), e.getY(), brushSize, brushSize);
}
repaint();
}
});
clearCanvas();
}
// Undoスタックに現在の状態を保存
private void saveToUndoStack() {
BufferedImage undoImage = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
Graphics2D g = undoImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
undoStack.push(undoImage);
redoStack.clear(); // 新しいアクションの後、Redoをクリア
}
// Undo機能
public void undo() {
if (!undoStack.isEmpty()) {
redoStack.push(image);
image = undoStack.pop();
g2 = image.createGraphics();
repaint();
}
}
// Redo機能
public void redo() {
if (!redoStack.isEmpty()) {
undoStack.push(image);
image = redoStack.pop();
g2 = image.createGraphics();
repaint();
}
}
// 色を設定
public void setColor(Color color) {
if (g2 != null) {
g2.setColor(color);
}
}
// ブラシサイズを設定
public void setBrushSize(int size) {
brushSize = size;
}
// キャンバスをクリア
public void clearCanvas() {
image = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.WHITE);
g2.fillRect(0, 0, image.getWidth(), image.getHeight());
g2.setPaint(Color.BLACK);
repaint();
}
// 描画イメージを取得
public BufferedImage getImage() {
return image;
}
// 描画イメージをセット
public void setImage(BufferedImage img) {
image = img;
g2 = image.createGraphics();
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
}
}