Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android canvas remove previous path being drawn

I am making a drawing app, and would like to implement an undo function to remove the immediate previous drawn path.

Coding:

private HashMap<Integer, Path> pathMap; // current Paths being drawn
private HashMap<Integer, Point> previousPointMap; // current Points
private Bitmap bitmap; // drawing area for display or saving
private Canvas bitmapCanvas; // used to draw on bitmap
private Paint paintScreen; // use to draw bitmap onto screen
private Paint paintLine; // used to draw lines onto bitmap

public DrawView(Context context, AttributeSet attrs) 
{
     super(context, attrs); // pass context to View's constructor
     this.context_new=context;

      paintScreen = new Paint(); // used to display bitmap onto screen

      // set the initial display settings for the painted line
      paintLine = new Paint();
      paintLine.setAntiAlias(true); // smooth edges of drawn line
      paintLine.setColor(Color.BLACK); // default color is black
      paintLine.setStyle(Paint.Style.STROKE); // solid line
      paintLine.setStrokeWidth(5); // set the default line width
      paintLine.setStrokeCap(Paint.Cap.ROUND); // rounded line ends
      pathMap = new HashMap<Integer, Path>();
      previousPointMap = new HashMap<Integer, Point>();
} // end DrawView constructor

@Override
protected void onDraw(Canvas canvas)  
{
    canvas.drawBitmap(bitmap, 0, 0, paintScreen); 
    for (Integer key : pathMap.keySet()) 
    canvas.drawPath(pathMap.get(key), paintLine);
} 

// called when the user finishes a touch    
   private void touchEnded(int lineID)   
   {
      Path path = pathMap.get(lineID); // get the corresponding Path
      bitmapCanvas.drawPath(path, paintLine); // draw to bitmapCanvas
      path.reset(); // reset the Path
      rememberLineId = lineID;
   } // end method touch_ended

//undo       
   private void undo()
   {
      Path path = pathMap.get(rememberLineId); // get the corresponding Path
      pathMap.remove(rememberLineId);
      bitmapCanvas.clearPath(path, paintLine); 
      path.reset(); // reset the Path
   } 

Question:

However, it seems there is no bitmapCanvas.clearPath this method? If then how could it be modified?

Codes Amended:

Declarations:

private Bitmap bitmap; // drawing area for display or saving
private Canvas bitmapCanvas; // used to draw on bitmap
private Paint paintScreen; // use to draw bitmap onto screen
private Paint paintLine; // used to draw lines onto bitmap
private HashMap<Integer, Path> pathMap; // current Paths being drawn
private HashMap<Integer, Point> previousPointMap; // current Points

private Bitmap bitmapBackup; 

OnSizeChanged

@Override
public void onSizeChanged(int w, int h, int oldW, int oldH)
{ 
   super.onSizeChanged(w, h, oldW, oldH);
   DoodlzViewWidth = w;    
   DoodlzViewHeight = h;

   bitmapBackup = Bitmap.createBitmap(getWidth(), DoodlzViewHeight, Bitmap.Config.ARGB_8888);     
   bitmap =       Bitmap.createBitmap(getWidth(), DoodlzViewHeight, Bitmap.Config.ARGB_8888);

   bitmapCanvas = new Canvas(bitmap);
   bitmap      .eraseColor(Color.WHITE); // erase the BitMap with white 
   bitmapBackup.eraseColor(Color.WHITE); 
} 

FirsttoBackup method, will invoke when the below TouchedStart performs

public void firsttobackup()
{ 
   bitmapBackup=bitmap;
       Toast message = Toast.makeText(getContext(), "backuped 123", Toast.LENGTH_SHORT);
   message.show(); //THIS TOAST CAN BE SUCESSFULLY PRESENTED when touching screen starting to draw
} 

OnDraw

@Override
protected void onDraw(Canvas canvas) 
{
canvas.drawBitmap(bitmap, 0, 0, paintScreen); 
    for (Integer key : pathMap.keySet()) 
     canvas.drawPath(pathMap.get(key), paintLine); 

}

OnTouchEvent

@Override
public boolean onTouchEvent(MotionEvent event) 
{        
  int action = event.getActionMasked(); // event type 
  int actionIndex = event.getActionIndex(); // pointer (i.e., finger)

  if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) 
  {
      firsttobackup(); //TOAST CAN SHOW "BACKUP 123"

      touchStarted(event.getX(actionIndex), event.getY(actionIndex), 
        event.getPointerId(actionIndex));
  }

Undo: user pressing the undo button will invoke this

public void undo()
{
  bitmap = bitmapBackup.copy(Bitmap.Config.ARGB_8888, true);
  bitmapCanvas = new Canvas(bitmap);        
}  

Question revised:

A method firsttobackup() is used now such that bitmapBackup would set = bitmap when executing OnTouchEvent touchStarted. I have put a toast in it and it is successfully to be presented "backup 123" when user press the screen and started to draw.

When user clicks undo button, it will invoke the undo method, but now pressing the undo button, no action can be seen...why?

like image 769
pearmak Avatar asked Feb 13 '13 07:02

pearmak


1 Answers

It is an old post, but I was looking for an answer for that issue as well. I was not satisfied with the chosen answer for that post and I found one myself after that. I actually think that having a full bitmap as a backup is not great memory-wise and it will limit the number of undo steps we can have.

I believe a better solution would be :

To have a stack of paths in your class

private Stack<Path> m_pathHistory = new Stack<Path>();

next to your canvas and your paintbrush (initialization skipped) :

private Canvas m_drawingCanvas;
private Paint m_paint;

Then every time a stroke is finished (on the touch up event), add a "clone" of the path to the undo history:

m_pathHistory.Push(new Path(currentPath));

And here is the undo function :

public void Undo()
{
    if(m_pathHistory.Count > 0)
    {
        m_pathHistory.Pop(); // Remove the last path from the history

        m_drawingCanvas.DrawColor(Color.Transparent, PorterDuff.Mode.Clear); // Clear the canvas with a transparent color

        // Draw the paths which are still in the history
        foreach (Path p in m_pathHistory)
        {
            m_drawingCanvas.DrawPath(p, m_paint);
        }
     }
}

The paths are much smaller to store in the memory than the full bitmaps, so we can have a much bigger history.

like image 70
Matheus Avatar answered Sep 21 '22 23:09

Matheus