TITLE:JPanelにマウスで自由曲線を描画
Posted by terai at 2005-12-19

JPanelにマウスで自由曲線を描画

  • category: swing folder: PaintPanel title: JPanelにマウスで自由曲線を描画 tags: [JPanel, MouseListener, MouseMotionListener] author: aterai pubdate: 2005-12-19T14:19:26+09:00 description: マウスをドラッグしてパネル上に自由曲線を描画します。 image: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTQ0y2U6WI/AAAAAAAAAgM/AAHllQ3_VHw/s800/PaintPanel.png

概要

マウスをドラッグしてパネル上に自由曲線を描画します。

#screenshot

サンプルコード

#spanend
#spanadd
class PaintPanel extends JPanel {
#spanend
  private static final Stroke STROKE = new BasicStroke(
      3f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
  private transient List<Shape> list;
  private transient Path2D path;
  private transient MouseAdapter handler;

#spandel
**サンプルコード [#jb2b9b9e]
#spanend
#spandel
#code{{
#spanend
#spandel
class PaintPanel extends JPanel implements MouseMotionListener, MouseListener {
#spanend
  private Point startPoint = new Point(-1,-1);
  private Point endPoint   = new Point(-1,-1);
  public PaintPanel() {
    super();
    addMouseMotionListener(this);
    addMouseListener(this);
  }
  public void paintComponent(Graphics g) {
    //super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g;
    g2d.setStroke(new BasicStroke(3.0F));
    g2d.setPaint(Color.BLACK);
    g2d.drawLine(startPoint.x, startPoint.y,
                 endPoint.x,   endPoint.y);
    startPoint = endPoint;
  }
  public void mouseDragged(MouseEvent e) {
    endPoint = e.getPoint();
    repaint();
  }
  public void mousePressed(MouseEvent e) {
    startPoint = e.getPoint();
  }
  public void mouseMoved(MouseEvent e) {}
  public void mouseExited(MouseEvent e) {}
  public void mouseEntered(MouseEvent e) {}
  public void mouseReleased(MouseEvent e) {}
  public void mouseClicked(MouseEvent e) {}
#spandel
}
#spanend
#spandel
View in GitHub: Java, Kotlin
 @Override public void updateUI() {
   removeMouseMotionListener(handler);
   removeMouseListener(handler);
   super.updateUI();
   handler = new MouseAdapter() {
     @Override public void mousePressed(MouseEvent e) {
       path = new Path2D.Double();
       list.add(path);
       Point p = e.getPoint();
       path.moveTo(p.x, p.y);
       repaint();
     }

解説

上記のサンプルでは、パネル上でマウスがドラッグされている場合、その軌跡を短い直線でつなぎ合わせて描画することで、お絵かきしています。
  • マウスがクリックされた場所を始点にする
  • ドラッグされた時の位置を終点にしてパネルをrepaint
  • paintComponentをオーバーライドして、上記の始点、終点で直線を描画
  • 次の直線のための始点を現在の終点に変更

コメント

  • マウス右ボタンをドラッグで消しゴム…のテスト -- terai
    #spanend
    #spandel
    import java.awt.*;
    #spanend
    #spandel
    import java.awt.event.*;
    #spanend
    #spandel
    import java.awt.geom.*;
    #spanend
    #spandel
    import java.awt.image.*;
    #spanend
    #spandel
    import javax.swing.*;
    #spanend
    #spandel
    
    #spanend
    #spandel
    class PaintPanel2 extends JPanel implements MouseMotionListener, MouseListener {
    #spanend
      public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
          public void run() {
            createAndShowGUI();
          @Override public void mouseDragged(MouseEvent e) {
            Point p = e.getPoint();
            path.lineTo(p.x, p.y);
            repaint();
          }
        });
        };
        addMouseMotionListener(handler);
        addMouseListener(handler);
        list = new ArrayList<Shape>();
      }
      public static void createAndShowGUI() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.getContentPane().add(new PaintPanel2());
        frame.setSize(320, 240);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    
      private final Polygon polygon = new Polygon();
      private Point startPoint = new Point(-1,-1);
      private BufferedImage offImage = null;
      private BufferedImage backImage = null;
      private TexturePaint texture  = makeTexturePaint();
      private int[] pix = new int[320 * 240];
      public PaintPanel2() {
        super();
        addMouseMotionListener(this);
        addMouseListener(this);
        offImage = new BufferedImage(320, 240, BufferedImage.TYPE_4BYTE_ABGR);
        PixelGrabber pg = new PixelGrabber(offImage, 0, 0, 320, 240, pix, 0, 320);
        try {
          pg.grabPixels();
        } catch (Exception e) {
          e.printStackTrace();
        }
        backImage = new BufferedImage(320, 240, BufferedImage.TYPE_4BYTE_ABGR);
        Graphics2D g2 = backImage.createGraphics();
        g2.setPaint(texture);
        g2.fillRect(0,0,320,240);
        g2.dispose();
      }
    #spandel
    
    #spanend
      private static BufferedImage makeBGImage() {
        Color color = new Color(200,150,100,50);
        int cs = 6, sz = cs*cs;
        BufferedImage img = new BufferedImage(sz,sz,BufferedImage.TYPE_4BYTE_ABGR);
        Graphics2D g2 = img.createGraphics();
        g2.setPaint(color);
        g2.fillRect(0,0,sz,sz);
        for (int i=0; i*cs<sz; i++) {
          for (int j=0; j*cs<sz; j++) {
            if ((i+j)%2==0) g2.fillRect(i*cs, j*cs, cs, cs);
      @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (list != null) {
          Graphics2D g2 = (Graphics2D) g.create();
          g2.setPaint(Color.BLACK);
          g2.setStroke(STROKE);
          for (Shape s : list) {
            g2.draw(s);
          }
          g2.dispose();
        }
        g2.dispose();
        return img;
      }
      private static TexturePaint makeTexturePaint() {
        BufferedImage img = makeBGImage();
        int w = img.getWidth(), h = img.getHeight();
        Rectangle2D r2d = new Rectangle2D.Float(0,0,w,h);
        return new TexturePaint(img, r2d);
      }
      @Override
      public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (backImage!=null) {
          ((Graphics2D)g).drawImage(backImage, 0, 0, this);
        }
        if (offImage!=null) {
          MemoryImageSource producer = new MemoryImageSource(320, 240, pix, 0, 320);
          g.drawImage(createImage(producer), 0, 0, null);
          g.dispose();
        }
      }
      int penc = 0x0;
      public void mouseDragged(MouseEvent e) {
        Point pt = e.getPoint();
        double xDelta = e.getX() - startPoint.getX();
        double yDelta = e.getY() - startPoint.getY();
        double delta = Math.max(Math.abs(xDelta), Math.abs(yDelta));
    #spandel
    
    #spanend
        double xIncrement = xDelta / delta;
        double yIncrement = yDelta / delta;
        double xStart = startPoint.x;
        double yStart = startPoint.y;
        for (int i=0; i<delta; i++) {
          Point p = new Point((int)xStart, (int)yStart);
          if (p.x<0 || p.y<0 || p.x>=320 || p.y>=240) break;
          pix[p.x + p.y * 320] = penc;
          if (p.x+1<320) pix[p.x + p.y * 320 +1 ]  = penc;
          if (p.x+2<320) pix[p.x + p.y * 320 +2 ]  = penc;
          if (p.y+1<240) pix[p.x + (p.y +1) * 320] = penc;
          if (p.y+2<240) pix[p.x + (p.y +2) * 320] = penc;
          if (p.x>1)     pix[p.x + p.y * 320 -1 ]  = penc;
          if (p.x>2)     pix[p.x + p.y * 320 -2 ]  = penc;
          if (p.y>1)     pix[p.x + (p.y -1) * 320] = penc;
          if (p.y>2)     pix[p.x + (p.y -2) * 320] = penc;
          repaint(p.x-2, p.y-2, 4, 4);
          xStart += xIncrement;
          yStart += yIncrement;
        }
        startPoint = pt;
      }
      private Rectangle getRepaintRectangle(Point srcPoint, Point destPoint) {
        polygon.reset();
        polygon.addPoint(srcPoint.x,  srcPoint.y);
        polygon.addPoint(destPoint.x, srcPoint.y);
        polygon.addPoint(destPoint.x, destPoint.y);
        polygon.addPoint(srcPoint.x,  destPoint.y);
        return polygon.getBounds();
      }
      public void mousePressed(MouseEvent e) {
        startPoint = e.getPoint();
        penc = (e.getButton()==MouseEvent.BUTTON1)?0xff000000:0x0;
      }
      public void mouseMoved(MouseEvent e) {}
      public void mouseExited(MouseEvent e) {}
      public void mouseEntered(MouseEvent e) {}
      public void mouseReleased(MouseEvent e) {}
      public void mouseClicked(MouseEvent e) {}
    }
    

解説

上記のサンプルでは、パネル上でマウスがドラッグされた場合その軌跡を短い直線でつなぎ合わせることで曲線を描画しています。
  • 新規Path2Dを生成してマウスがクリックされた場所をPath2D.moveTo(...)で始点に設定
  • ドラッグされた時の位置をPath2D.lineTo(...)で終点にしてパネルをrepaint()
  • paintComponent(...)をオーバーライドして、上記の直線のリスト(Path2Dのリスト)を描画
  • 次の直線のための始点を現在の終点に変更

参考リンク

コメント