Search code examples
javaimageswinggraphics2d

How to draw thin line with no gap while dragging the cursor?


I have this following class, which refresh a jpeg file in layer 0 and layer 1 is used to draw/paint/sketch up anything related to smash things. But in my drawing when I want to do a thin line, it breaks. Because the mouse cursor movement needs to be slower.

How to resolve on fast mouse move, that the line remains joined?

Image with mouse drag dotted line

Annotation.java

package test;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Annotation {

  // Image
  private static Image backgroundImage;
  private static BufferedImage _bufImage = null;
  
  // Enum 
  public  static enum Shape { RECTANGLE, OVAL, LINE }
  private static enum State { IDLE, DRAGGING }       
  
  private static final Shape INIIIAL_SHAPE = Shape.RECTANGLE;
  private static final Color INITIAL_COLOR = Color.RED;  
  private static Shape _shape = INIIIAL_SHAPE;
  private static Color _color = INITIAL_COLOR;
  
  private static State _state = State.IDLE;
  private static Point _start = null; 
  private static Point _end   = null;
  
  // JPanel
  private static JPanel p;
  private static JPanel mp;
   
  /* Run: */
  public static void main(String args[]) {   
    c();
  }

  /* GUI */
  public static void c() {      
    try {
      backgroundImage = ImageIO.read(new File("/var/tmp/test.jpeg"));
    } catch (IOException e) {
      e.printStackTrace();
    }
    
    myTimer();
    loadAnnotation();
    loadBackground();
    
    JFrame f; 
    f = new JFrame();    
    f.setLayout(new BorderLayout());
    f.add(mp);
    f.pack();
    f.setVisible(true);    
  }

  /* 5 seconds to load picture */
  public static void myTimer() {   
    javax.swing.Timer t = new javax.swing.Timer(5000, new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        try {
          backgroundImage = ImageIO.read(new File("/var/tmp/test.jpeg"));    
          mp.repaint();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    });
    t.start();
  }
  
  /* Layer 0: 
   * Load background picture */
  public static void loadBackground() {    
    mp = new JPanel() {
      public void paintComponent(Graphics g) {       
        super.paintComponent(g);
        g.drawImage(backgroundImage, 0, 0, 1024, 600, null);            
      }
      public Dimension getPreferredSize() {
        return new Dimension(1024, 600);
      }
    };    
    mp.add(p);        
  }

  /* Layer 1: 
   * Annotation: Draw on top of background picture anything! */
  public static void loadAnnotation() {
        
    p = new JPanel() {
      public void paintComponent(Graphics g) {       
        Graphics2D g2 = (Graphics2D)g;
        g2.setColor(Color.RED);
        if (_bufImage == null) {        
            int w = this.getWidth();
            int h = this.getHeight();
            _bufImage  = new BufferedImage(1024,600, BufferedImage.TRANSLUCENT);
            Graphics2D gc = _bufImage.createGraphics();
        }
        
        g2.drawImage(_bufImage, null, 0, 0);        
        if (_state == State.DRAGGING) {
          g2.drawLine(_start.x, _start.y, _end.x  , _end.y);
        }        
      }

      public Dimension getPreferredSize() {
        return new Dimension(1024, 600);
      }      
    };
    
    p.setLayout(new FlowLayout());
    p.addMouseListener(new MouseListener() {
      @Override
      public void mouseClicked(MouseEvent me) {
      }

      @Override
      public void mousePressed(MouseEvent me) {
      }

      @Override
      public void mouseReleased(MouseEvent me) {
        //_state = State.IDLE;
        _state = State.IDLE;
      }

      @Override
      public void mouseEntered(MouseEvent me) {
      }

      @Override
      public void mouseExited(MouseEvent me) {
      }
    });
    
    p.addMouseMotionListener(new MouseMotionListener() {
      
      @Override
      public void mouseDragged(MouseEvent me) {
        System.out.println("drag");        
        _state = State.DRAGGING; 
        _start = me.getPoint();
        _end   = _start;
        if (_state == State.DRAGGING) {
            Graphics2D g2 = _bufImage.createGraphics();
            g2.setColor(Color.red);
            g2.setStroke(new BasicStroke(90));   
            g2.fillOval(_start.x, _start.y, 10, 10);            
            p.repaint();                        
        }         
      }
      
      @Override
      public void mouseMoved(MouseEvent me) {
        System.out.println("move");
      }
    });
    
    JButton pm = new JButton("+");
    pm.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent ae) {
      }
    });    
    p.add(pm);       
    p.setOpaque(true);    
  }
  
}

Solution

  • enter image description here

    import java.awt.*;
    import java.awt.event.*;
    import java.awt.image.BufferedImage;
    import java.net.URL;
    import javax.imageio.ImageIO;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class Annotation {
    
      // Image
      private static Image backgroundImage;
      private static BufferedImage _bufImage = null;
    
      // Enum
      public  static enum Shape { RECTANGLE, OVAL, LINE }
      private static enum State { IDLE, DRAGGING }
    
      private static final Shape INIIIAL_SHAPE = Shape.RECTANGLE;
      private static final Color INITIAL_COLOR = Color.RED;
      private static Shape _shape = INIIIAL_SHAPE;
      private static Color _color = INITIAL_COLOR;
    
      private static State _state = State.IDLE;
      private static Point _start = null;
      private static Point _end   = null;
    
      // JPanel
      private static JPanel p;
      private static JPanel mp;
    
      /* Run: */
      public static void main(String args[]) {
        c();
      }
    
      /* GUI */
      public static void c() {
        try {
            URL url = new URL("http://pscode.org/media/stromlo2.jpg");
          backgroundImage = ImageIO.read(url);
        } catch (Exception e) {
          e.printStackTrace();
        }
    
        loadAnnotation();
        loadBackground();
    
        JFrame f;
        f = new JFrame();
        f.setLayout(new BorderLayout());
        f.add(mp);
        f.pack();
        f.setVisible(true);
      }
    
      /* Layer 0:
       * Load background picture */
      public static void loadBackground() {
        mp = new JPanel() {
          public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), null);
          }
          public Dimension getPreferredSize() {
            return new Dimension(backgroundImage.getWidth(this), backgroundImage.getHeight(this));
          }
        };
        mp.add(p);
      }
    
      /* Layer 1:
       * Annotation: Draw on top of background picture anything! */
      public static void loadAnnotation() {
    
        p = new JPanel() {
          public void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D)g;
            g2.setColor(Color.RED);
            if (_bufImage == null) {
                int w = this.getWidth();
                int h = this.getHeight();
                _bufImage  = new BufferedImage(1024,600, BufferedImage.TRANSLUCENT);
                Graphics2D gc = _bufImage.createGraphics();
            }
    
            g2.drawImage(_bufImage, null, 0, 0);
            if (_state == State.DRAGGING) {
              g2.drawLine(_start.x, _start.y, _end.x  , _end.y);
            }
          }
    
          public Dimension getPreferredSize() {
            return new Dimension(1024, 600);
          }
        };
    
        p.setLayout(new FlowLayout());
        p.addMouseListener(new MouseListener() {
          @Override
          public void mouseClicked(MouseEvent me) {
          }
    
          @Override
          public void mousePressed(MouseEvent me) {
          }
    
          @Override
          public void mouseReleased(MouseEvent me) {
            //_state = State.IDLE;
            _state = State.IDLE;
          }
    
          @Override
          public void mouseEntered(MouseEvent me) {
          }
    
          @Override
          public void mouseExited(MouseEvent me) {
          }
        });
    
        p.addMouseMotionListener(new MouseMotionListener() {
    
          @Override
          public void mouseDragged(MouseEvent me) {
            _state = State.DRAGGING;
            _end   = me.getPoint();
            if (_state == State.DRAGGING) {
                Graphics2D g2 = _bufImage.createGraphics();
                g2.setColor(Color.red);
                g2.setStroke(new BasicStroke(2));
                g2.drawLine(_start.x, _start.y, _end.x, _end.y);
                p.repaint();
            }
            _start = _end;
          }
    
          @Override
          public void mouseMoved(MouseEvent me) {
            //System.out.println("move");
            _start = me.getPoint();
          }
        });
    
        JButton pm = new JButton("+");
        pm.addActionListener(new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent ae) {
          }
        });
        p.add(pm);
        p.setOpaque(true);
      }
    
    }