【问题标题】:Efficient way to draw paint using mouse on canvas在画布上使用鼠标绘制颜料的有效方法
【发布时间】:2020-11-23 20:02:05
【问题描述】:

我有一个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);//Translate ecllipse so that the centre of it's bounding box is exactly at the cursor location for more accurate blobs  
   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);}
}

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

每当用户拖动鼠标时,使用当前画笔设置在当前位置添加一个 blob,并在 paint() 内部循环遍历所有 blob 并重绘它们。

final class Painter extends Canvas
{
 private Brush brush=new Brush(5,Color.red);//Can Change
 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(brush,m.getPoint());

   repaint();
  }    
 }
}

您已经可以在此处看到问题所在。列表的大小呈指数增长,我的应用程序迅速变慢。有没有更有效的方法来做到这一点?

【问题讨论】:

  • 您是否正在尝试创建 ms 绘画?有趣的项目,开源吧。
  • 我的聊天应用程序的迷你版。有望在今年年底前在 GitHub 上发布 :)
  • “列表的大小呈指数增长” 不,它以线性方式增长(除非我在上面的代码中遗漏了什么)。 非常不同的东西。 “..我的应用程序很快变慢了。” 我不相信。发一个minimal reproducible example,我们可以在本地测试。

标签: java swing awt paint


【解决方案1】:

更有效的方法是使用 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() & 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 < 0) {
                angle += 2 * Math.PI;
            }
            @SuppressWarnings("unused")
            double distance = MathUtils.distance(mLastPoint, p) * 1.5;
            if (angle < Math.PI / 4 || angle > 7 * Math.PI / 4 || Math.abs(Math.PI - angle) < Math.PI / 4) {
                for (int i = 0; i < 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 < 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;
    }
}

【讨论】:

  • 啊,是的,这里的问题是我需要能够“撤消”我之前的操作。这里的故事是我正在为我的聊天应用程序创建一个迷你图像编辑器,用户可以在发送图像之前对图像进行简单的绘制操作。当他按 Ctrl+z 时,我需要能够撤消绘画的每一步,就像 Ms Paint 一样。在这里,我只能通过重绘原始图像来撤消整个绘制操作。有什么建议吗?
  • @RVISHAL 看看与 PaintArea 相同的 sourceforge 项目/目录中的 PaintArea2,我记得它包括撤消功能。就我个人而言,我一直发现撤消在即将撤消的权利方面实施起来很棘手 - 不是太少,但也不是太多
  • 谢谢您,我确实看过它,这很棘手,我想我会跳过整个撤消操作并使用您的方法。我找到了一种去除油漆的替代方法,只需根据用户拖动的位置使用原始图像的subSection 对其进行绘画,并且效果很好。点赞
猜你喜欢
  • 1970-01-01
  • 2015-01-04
  • 1970-01-01
  • 1970-01-01
  • 2021-08-18
  • 2011-04-18
  • 2016-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多