0

There are multiple scribble apps on here that have an undo button. I haven't implemented those because my code is different, but I have looked at the concepts. I.E storing points in an array.

When the program detects touch events:

@Override
public boolean onTouchEvent(MotionEvent event) {

    float touchX = event.getX();    //Gets the fingers x position
    float touchY = event.getY();    //gets the fingers y position

    PointF points = new PointF();   //init a new PointF
    points.x = touchX;              //store the coordinates in the Point object
    points.y = touchY;

    _pointList.add(points);         //add this to the list of Points (array)

    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            _path.moveTo(touchX, touchY); //Set the beginning of the next contour to the point (x,y)
                                            //will start drawing from where the last point was
            break;
        case MotionEvent.ACTION_MOVE:
            _path.lineTo(touchX, touchY); 
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    invalidate();
    return true;
}

In theory the _pointList Array should capture all the touch inputs in order. And this is evident, since the console displays the size of the array.

In the onDraw method, it should loop through all of the points in the a_pointList List. Since it contains all of the points that the user has interacted on the screen, then in theory it should draw the lines from memory.

  @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    for (PointF points : _pointList) {
        _path.moveTo(points.x, points.y);
        _path.lineTo(points.x, points.y);
        _canvas.drawPath(_path, _paint);
    }
    canvas.drawBitmap(_bitmap, 0, 0, _paint);
}

When the application runs I am able to draw on the screen, and due to the clear method the screen clears.

  public void clear(){
    _pointList.clear();// empty the list that stores the points
    _bitmap = Bitmap.createBitmap(1000,1000,
            Bitmap.Config.ARGB_8888);

    _canvas = new Canvas(_bitmap);
    _path = new Path();
    _paint = new Paint(Paint.DITHER_FLAG);

    //Added later..
    _paint.setColor(Color.RED);
    _paint.setAntiAlias(true);
    _paint.setStyle(Paint.Style.STROKE);

    //empties the screen
    invalidate();
}

However, in my undo method, it should drop one of the points (that contains the users X and Y touch inputs) from the _pointList List. After dropping the point, the screen should redraw all of the lines from memory.

public void undo() {

    Log.d("Number", "undo:" + _pointList.size()  );
    if (_pointList.size()>0){
        _bitmap = Bitmap.createBitmap(1000,1000,
            Bitmap.Config.ARGB_8888);

    _canvas = new Canvas(_bitmap);
    _path = new Path();
    _paint = new Paint(Paint.DITHER_FLAG);

    //Added later..
    _paint.setColor(Color.RED);
    _paint.setAntiAlias(true);
    _paint.setStyle(Paint.Style.STROKE);

    _pointList.remove(_pointList.size() - 1);


    invalidate();
    }
}

This method has the same effect as the 'clear' method and does not redraw the lines,

My other alternatives to the undo button was putting the bitmaps into an array, but I'm sure that would cause memory issues since it's a dynamic program.

Question: Why doesn't the 'invalidate' call from the 'undo' method update the screen?

Update:

The whole code:

--Draw--

package com.example.moynul.myapplication;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by moynu on 10/12/2015.
 */

    public  class Draw extends View {


    private Paint _paint = new Paint();
    private Path _path = new Path();
    private Bitmap _bitmap;
    private Canvas _canvas;
    private  List<PointF> _pointList = new ArrayList<PointF>();



    public Draw(Context context) {
        super(context);
        init(null, 0);


    }


    public Draw(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs,0);
    }
    public Draw(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs, defStyleAttr);
    }

    private void init(AttributeSet attrs, int defStyleAttr) {
        _paint.setColor(Color.RED);
        _paint.setAntiAlias(true);
        _paint.setStyle(Paint.Style.STROKE);
        _bitmap = Bitmap.createBitmap (1080, 1920, Bitmap.Config.ARGB_8888);
        _canvas = new Canvas(_bitmap);
    }



    @Override
    public boolean onTouchEvent(MotionEvent event) {

        float touchX = event.getX();    //Gets the fingers x position
        float touchY = event.getY();    //gets the fingers y position

        PointF points = new PointF();   //init a new PointF
        points.x = touchX;              //store the coordinates in the Point object
        points.y = touchY;

        _pointList.add(points);         //add this to the list of Points (array)

        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                _path.moveTo(touchX, touchY); //Set the beginning of the next contour to the point (x,y)
                                                //will start drawing from where the last point was
                break;
            case MotionEvent.ACTION_MOVE:
                _path.lineTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        invalidate();
        return true;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (PointF points : _pointList) {
            _path.moveTo(points.x, points.y);
            _path.lineTo(points.x, points.y);
            _canvas.drawPath(_path, _paint);
        }
        canvas.drawBitmap(_bitmap, 0, 0, _paint);
    }

    public void clear(){
        _pointList.clear();// empty the list that stores the points
        _bitmap = Bitmap.createBitmap(1000,1000,
                Bitmap.Config.ARGB_8888);

        _canvas = new Canvas(_bitmap);
        _path = new Path();
        _paint = new Paint(Paint.DITHER_FLAG);

        //Added later..
        _paint.setColor(Color.RED);
        _paint.setAntiAlias(true);
        _paint.setStyle(Paint.Style.STROKE);

        //empties the screen
        invalidate();
    }


    public void undo() {

        Log.d("Number", "undo:" + _pointList.size());
        if (_pointList.size()>0){

            _pointList.remove(_pointList.size() - 1);

            _bitmap = Bitmap.createBitmap(1000,1000,
                Bitmap.Config.ARGB_8888);

        _canvas = new Canvas(_bitmap);
        _path = new Path();
        _paint = new Paint(Paint.DITHER_FLAG);

        //Added later..
        _paint.setColor(Color.RED);
        _paint.setAntiAlias(true);
        _paint.setStyle(Paint.Style.STROKE);

        invalidate();
        }
    }
}
Moynul
  • 635
  • 1
  • 8
  • 30
  • Please upload whole class of view, It will help to solve at my end – Rohit Patil Dec 10 '15 at 22:59
  • @RohitPatil the page has been updated to show the whole code. – Moynul Dec 10 '15 at 23:08
  • You need to rethink your logic. In the `onDraw()` method, as you iterate over the points to update the Path, you first `moveTo()` a point, then `lineTo()` that same point. This effectively does nothing, which is why your image blanks after the undo. The only reason you're able to draw at all is because you're moving the Path in the `onTouchEvent()`, as well. However, in the undo, you're resetting the Path, so the next `onDraw()` is just looping over the points, doing that same "nothing" for each point, but without the Path updates that were happening in `onTouchEvent()`. – Mike M. Dec 11 '15 at 00:25
  • @Mike.M programming wise, how I will i be able to over come this problem? – Moynul Dec 11 '15 at 12:22
  • I can't be certain, as I don't know exactly what your drawing app is supposed to do. However, if it's meant to be like any other generic paint app, you should be saving `Path`s in your List, rather than `Point`s. If the user draws by moving their finger on the screen, then a single drawing action is going to consist of many `Point`s in a single `Path`. It wouldn't make sense for the undo to just remove one of those `Point`s. (Btw, to ping a user, the @name needs to be pretty exact, or they won't get it. I just happened to revisit this post, and saw your comment.) – Mike M. Dec 11 '15 at 14:13

2 Answers2

0

Change following inside onDraw() for loop

canvas.drawPath(_path, _paint);

Hope it will work

Rohit Patil
  • 1,068
  • 8
  • 9
  • This method directly writes to the canvas, and not the bitmap. It tends to slow down the program and then crash it after a few times, unless the array is cleared by hitting the clear button. – Moynul Dec 10 '15 at 23:20
0

You have an issue in your onDraw method, you are always drawing the _bitmap on the same positions (0,0) not on the path. Replace your onDraw code with my code below:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    for (PointF points : _pointList) {
        _path.moveTo(points.x, points.y);
        _path.lineTo(points.x, points.y);
        _canvas.drawPath(_path, _paint);

         canvas.drawBitmap(_bitmap, points.x, points.y, _paint);
    }
}
Arlind Hajredinaj
  • 8,380
  • 3
  • 30
  • 45
  • the drawBitmap method draws the specified bitmap, with its top/left corner at (x,y), using the specified paint, transformed by the current matrix. - API. This causes the program to now draw the bitmap all over the screen, in respect to the users location. Since _pointList contains the users touch inputs. Hence drawing a bitmap for each points in the array, at the location. In conclusion, this causes a cool 3-D effect, but slows down the program. – Moynul Dec 10 '15 at 23:27