Skip to content

Instantly share code, notes, and snippets.

@skht777
Last active February 12, 2017 11:15
Show Gist options
  • Select an option

  • Save skht777/7d4d879a2396101664a82566ba0c6b09 to your computer and use it in GitHub Desktop.

Select an option

Save skht777/7d4d879a2396101664a82566ba0c6b09 to your computer and use it in GitHub Desktop.
雑なペイント
package paint;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author skht777
*/
public class MainFrame extends JFrame {
private MainFrame() {
super();
setSize(700, 600);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent) {
System.exit(0);
}
});
PaintCanvas canvas = new PaintCanvas();
PaintTool tool = new PaintTool(canvas);
getContentPane().setLayout(new BorderLayout(10, 10));
getContentPane().add(tool, BorderLayout.WEST);
getContentPane().add(canvas, BorderLayout.CENTER);
// 全てのコンポーネントにキーイベントぶん投げる
List<Component> list = new ArrayList<>(Arrays.asList(getComponents()));
while (!list.isEmpty()) {
Container c = (Container) list.remove(0);
list.addAll(Arrays.asList(c.getComponents()));
c.addKeyListener(canvas.getKeyListener());
}
repaint(); // PaintToolを正しい形にする
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new MainFrame().setVisible(true));
}
}
package paint;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
/**
* @author skht777
*/
public class PaintCanvas extends JPanel implements ShapeObserver {
private final List<BufferedImage> histrory;
private final AffineTransform at;
private Shape shape;
private Color color;
private final MouseAdapter adpter = new MouseAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
draw(e.getX(), e.getY());
repaint();
}
@Override
public void mousePressed(MouseEvent e) {
histrory.add(createAlphaImage());
draw(e.getX(), e.getY());
repaint();
}
};
public PaintCanvas() {
super();
histrory = new ArrayList<>();
at = new AffineTransform();
setBackground(Color.white);
addMouseListener(adpter);
addMouseMotionListener(adpter);
}
// ctr(⌘) + zでundo
public KeyListener getKeyListener() {
return new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
int mask = System.getProperty("os.name").equals("Mac OS X") ?
InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK;
if (e.getKeyCode() == KeyEvent.VK_Z && e.getModifiersEx() == mask
&& !histrory.isEmpty()) {
histrory.remove(histrory.size() - 1);
repaint();
}
}
};
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D g2 = (Graphics2D) g;
histrory.forEach(im -> g2.drawImage(im, 0, 0, null));
}
// Imageを重ねるために透明なレイヤーを用意する
private BufferedImage createAlphaImage() {
final int width = getWidth(), height = getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g = (Graphics2D) image.getGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
g.fill(new Rectangle2D.Double(0, 0, width, height));
g.setPaintMode();
g.dispose();
return image;
}
private void draw(int x, int y) {
final Graphics2D g = (Graphics2D) histrory.get(histrory.size() - 1).getGraphics();
// Shapeの現在位置と描画位置の相対位置を求めて平行移動する変換式を設定
at.setToTranslation(x - shape.getBounds2D().getX(), y - shape.getBounds2D().getY());
g.setColor(color);
g.fill(at.createTransformedShape(shape));
g.dispose();
}
@Override
public void updateShape(Shape s) {
shape = s;
}
@Override
public void updateColor(Color c) {
color = c;
}
}
package paint;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.function.Consumer;
import java.util.stream.IntStream;
/**
* @author skht777
*/
public class PaintTool extends JPanel {
private final ShapeObserver observer;
private static final int BASE_BOLD = 3;
private Shape2D shape;
private int size;
// 描画する図形の識別用
private enum Shape2D {
RECT(new Palette(Color.white)) {
@Override
Shape createShape(int size) {
return new Rectangle2D.Double(0, 0, size, size);
}
},
ELLIPSE(new Palette(Color.black)) {
@Override
Shape createShape(int size) {
return new Ellipse2D.Double(0, 0, size, size);
}
};
private final Palette palette;
private Shape2D(Palette palette) {
this.palette = palette;
}
Palette getPalette() {
return palette;
}
abstract Shape createShape(int size);
}
// カラーパレット
private static class Palette {
private Color color;
Palette(Color initialColor) {
color = initialColor;
}
public void colorChoose() {
Color c = JColorChooser.showDialog(null, "色選択", color);
if (c != null) color = c;
}
public Color getColor() {
return color;
}
}
// カラーパレット用のパネル
private class PalettePanel extends JPanel {
private Palette palette;
PalettePanel(Palette palette) {
this.palette = palette;
addMouseListener(PaintTool.this.implMouseClicked(e -> {
palette.colorChoose();
repaint();
PaintTool.this.update();
}));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
final int size = 30;
final Graphics2D g2 = (Graphics2D) g;
// 現在の色を選択して描画
g2.setColor(palette.getColor());
g2.fill(new Rectangle2D.Double((getWidth() - size) / 2, 10, size, size));
}
}
public PaintTool(ShapeObserver observer) {
shape = Shape2D.ELLIPSE;
size = BASE_BOLD;
this.observer = observer;
setLayout(new GridLayout(2, 1, 5, 5));
add(getToolBox());
add(getOptionBox());
update();
}
private JPanel getLayoutedPanel(int row, int col) {
JPanel panel = new JPanel();
panel.setBorder(new EmptyBorder(0, 5, 0, 0));
panel.setLayout(new GridLayout(row, col, 0, 5));
return panel;
}
private JPanel getPanelWithBorder(int row, int col) {
JPanel panel = getLayoutedPanel(row, col);
panel.setBorder(new LineBorder(Color.black));
return panel;
}
// 描画モードの設定ボックス
private JPanel getToolBox() {
JPanel tool = getLayoutedPanel(5, 2);
JButton pen = new JButton("書く");
pen.addMouseListener(implMouseClicked(e -> {
shape = Shape2D.ELLIPSE;
update();
}));
JButton eraser = new JButton("消す");
eraser.addMouseListener(implMouseClicked(e -> {
shape = Shape2D.RECT;
update();
}));
tool.add(pen);
tool.add(eraser);
return tool;
}
// 描画オプションの設定ボックス
private JPanel getOptionBox() {
JPanel option = getLayoutedPanel(2, 1);
// 描画の太さの設定(MSペイントのパクリ)
JPanel bold = getPanelWithBorder(4, 1);
IntStream.rangeClosed(1, 4).map(i -> i * BASE_BOLD)
.mapToObj(i -> {
// TODO クラス化を検討
JPanel panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D g2 = (Graphics2D) g;
g2.fill(new Rectangle2D.Double(5, (getHeight() - i) / 2.0, getWidth() - 10, i));
}
};
panel.addMouseListener(implMouseClicked(e -> {
// 選んだやつの色を変える
bold.getComponent(size / BASE_BOLD - 1).setBackground(bold.getBackground());
panel.setBackground(Color.cyan);
size = i;
update();
}));
return panel;
}).forEach(bold::add);
bold.getComponent(0).setBackground(Color.cyan);
// カラーパレットの設定
JPanel palette = getPanelWithBorder(2, 1);
palette.add(new PalettePanel(Shape2D.ELLIPSE.getPalette()));
palette.add(new PalettePanel(Shape2D.RECT.getPalette()));
option.add(bold);
option.add(palette);
return option;
}
// オブザーバに現在の設定をぶん投げる
private void update() {
observer.upadate(shape.createShape(size), shape.getPalette().getColor());
}
private MouseListener implMouseClicked(Consumer<MouseEvent> impl) {
return new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
impl.accept(e);
}
};
}
}
package paint;
import java.awt.*;
/**
* @author skht777
*/
interface ShapeObserver {
void updateShape(Shape s);
void updateColor(Color c);
default void upadate(Shape s, Color c) {
updateShape(s);
updateColor(c);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment