在画布上使用鼠标绘制图形的高效方法

huangapple go评论69阅读模式
英文:

Efficient way to draw paint using mouse on canvas

问题

我有一个Brush

final class Brush {
    private final int size;
    private final Color color;
    private final Ellipse2D.Double blob = new Ellipse2D.Double();

    private Brush(int size, Color color) {
        this.size = size;
        this.color = color;
    }

    void paint(Graphics2D g2d, Point location) {
        g2d.setColor(color);
        blob.setFrame(location.x - (size / 2.0), location.y - (size / 2.0), size, size);
        g2d.fill(blob);
    }
}

我有一个Blob类,用于跟踪用户当前的笔刷设置以及用户之前拖动鼠标的位置,以便在那里绘制一个斑点。

final class Blob {
    final Brush brush;
    final Point location;

    private Blob(Brush brush, Point location) {
        this.brush = brush;
        this.location = location;
    }

    private void paint(Graphics2D g) {
        brush.paint(g, location);
    }
}

最后是我的绘制逻辑,非常简单。

每当用户拖动鼠标时,在当前位置使用当前笔刷设置添加一个斑点,并在paint()中循环遍历所有斑点并重新绘制它们。

final class Painter extends Canvas {
    private Brush brush = new Brush(5, Color.red);
    private final ArrayList<Blob> blobs = new ArrayList();

    private Painter() {
        addMouseMotionListener(new Dragger());
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);

        blobs.forEach(blob -> blob.paint(g));
    }

    private final class Dragger extends MouseAdapter {
        @Override
        public void mouseDragged(MouseEvent m) {
            blobs.add(new Blob(brush, m.getPoint()));
            repaint();
        }
    }
}

你已经可以看到问题了。列表的大小呈指数增长,我的应用程序很快变慢。有没有更高效的方法来做这个?

英文:

I have a Brush class

 final class Brush
 {
  private final int size;
  private final Color color;
  private final Ellipse2D.Double blob=new Ellipse2D.Double();

  private Brush(int size,Color color)
  {
   this.size=size;
   this.color=color;
  }

  void paint(Graphics2D g2d,Point location)
  {
   g2d.setColor(color);    
   blob.setFrame(location.x-(size/2.0),location.y-(size/2.0),size,size);//Translate ecllipse so that the centre of it&#39;s bounding box is exactly at the cursor location for more accurate blobs  
   g2d.fill(blob);
  }
 }

I have a Blob class which keeps track of the user's current brush settings and where the user previously dragged his mouse so as to remember to draw a blob there.

final class Blob
{
 final Brush brush;
 final Point location;

 private Blob(Brush brush,Point location)
 {
  this.brush=brush;
  this.location=location;
 }

 private void paint(Graphics2D g){brush.paint(g,location);}
}

Finally my paint logic which is very simple.

Whenever the user drags his mouse add a blob at that current location with the current brush settings and inside paint() loop through all blobs and redraw them.

final class Painter extends Canvas
{
 private Brush brush=new Brush(5,Color.red);//Can Change
 private final ArrayList&lt;Blob&gt; blobs=new ArrayList(); 

 private Painter(){addMouseMotionListener(new Dragger());}

 @Override
 public void paint(Graphics g)
 {
  super.paint(g);

  blobs.forEach(blob-&gt;blob.paint(g));
 }

 private final class Dragger extends MouseAdapter
 {
  @Override
  public void mouseDragged(MouseEvent m)
  {
   blobs.add(brush,m.getPoint());

   repaint();
  }    
 }
}

You can already see the problem here. The size of the list grows exponentially and my app quickly slows down. Is there an more efficient way to do this?

答案1

得分: 2

使用BufferedImage来进行绘制,并在paintComponent中绘制BufferedImage是更高效的方式。

PaintArea中提取的代码如下:

public void paintComponent(Graphics g) {
    if (mSizeChanged) {
        handleResize();
    }
    g.drawImage(mImg, 0, 0, null);
}

protected class MListener extends MouseAdapter implements MouseMotionListener {
    Point mLastPoint;
    public void mouseDragged(MouseEvent me) {
        Graphics g = mImg.getGraphics();
        if ((me.getModifiers() &amp; InputEvent.BUTTON1_MASK) != 0) {
            g.setColor(mColor1);
        } else {
            g.setColor(mColor2);
        }
        Point p = me.getPoint();
        if (mLastPoint == null) {
            g.fillOval(p.x - mBrushSize / 2, p.y - mBrushSize / 2, mBrushSize, mBrushSize);
        } else {
            g.drawLine(mLastPoint.x, mLastPoint.y, p.x, p.y);
            double angle = MathUtils.angle(mLastPoint, p);
            if (angle &lt; 0) {
                angle += 2 * Math.PI;
            }
            @SuppressWarnings(&quot;unused&quot;)
            double distance = MathUtils.distance(mLastPoint, p) * 1.5;
            if (angle &lt; Math.PI / 4 || angle &gt; 7 * Math.PI / 4 || Math.abs(Math.PI - angle) &lt; Math.PI / 4) {
                for (int i = 0; i &lt; mBrushSize / 2; i ++) {
                    g.drawLine(mLastPoint.x, mLastPoint.y + i, p.x, p.y + i);
                    g.drawLine(mLastPoint.x, mLastPoint.y - i, p.x, p.y - i);
                }
            } else {
                for (int i = 0; i &lt; mBrushSize / 2; i ++) {
                    g.drawLine(mLastPoint.x + i, mLastPoint.y, p.x + i, p.y);
                    g.drawLine(mLastPoint.x  - i, mLastPoint.y, p.x - i, p.y);
                }                    
            }
        }
        mLastPoint = p;
        g.dispose();
        repaint();
    }

    public void mouseMoved(MouseEvent me) {}

    public void mouseReleased(MouseEvent me) {
        mLastPoint = null;
    }
}
英文:

The much more efficient way to do this is to use a BufferedImage for your drawing, and than painting the BufferedImage in paintComponent

Code taken from PaintArea:

public void paintComponent(Graphics g) {
if (mSizeChanged) {
handleResize();
}
g.drawImage(mImg, 0, 0, null);
}
protected class MListener extends MouseAdapter implements MouseMotionListener {
Point mLastPoint;
public void mouseDragged(MouseEvent me) {
Graphics g = mImg.getGraphics();
if ((me.getModifiers() &amp; InputEvent.BUTTON1_MASK) != 0) {
g.setColor(mColor1);
} else {
g.setColor(mColor2);
}
Point p = me.getPoint();
if (mLastPoint == null) {
g.fillOval(p.x - mBrushSize / 2, p.y - mBrushSize / 2, mBrushSize, mBrushSize);
//g.drawLine(p.x, p.y, p.x, p.y);
}
else {
g.drawLine(mLastPoint.x, mLastPoint.y, p.x, p.y);
//g.fillOval(p.x - mBrushSize / 2, p.y - mBrushSize / 2, mBrushSize, mBrushSize);
double angle = MathUtils.angle(mLastPoint, p);
if (angle &lt; 0) {
angle += 2 * Math.PI;
}
@SuppressWarnings(&quot;unused&quot;)
double distance = MathUtils.distance(mLastPoint, p) * 1.5;
if (angle &lt; Math.PI / 4 || angle &gt; 7 * Math.PI / 4 || Math.abs(Math.PI - angle) &lt; Math.PI / 4) {
for (int i = 0; i &lt; mBrushSize / 2; i ++) {
g.drawLine(mLastPoint.x, mLastPoint.y + i, p.x, p.y + i);
g.drawLine(mLastPoint.x, mLastPoint.y - i, p.x, p.y - i);
}
}
else {
for (int i = 0; i &lt; mBrushSize / 2; i ++) {
g.drawLine(mLastPoint.x + i, mLastPoint.y, p.x + i, p.y);
g.drawLine(mLastPoint.x  - i, mLastPoint.y, p.x - i, p.y);
}					
}
}
mLastPoint = p;
g.dispose();
repaint();
}
public void mouseMoved(MouseEvent me) {}
public void mouseReleased(MouseEvent me) {
mLastPoint = null;
}
}

huangapple
  • 本文由 发表于 2020年8月4日 02:12:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/63234768.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定