【问题标题】:How to implement undo/redo in my drawing app如何在我的绘图应用程序中实现撤消/重做
【发布时间】:2015-07-28 16:44:33
【问题描述】:

我创建了一个应用程序来绘制并想实现功能撤消/重做,我尝试了各种冲​​浪的方法,但都没有奏效,有人可以帮助我吗?

这是我的代码:

变量

'public class MainDrawingView extends View {
public MainDrawingView(Context context, AttributeSet attrs) {

    super(context, attrs);
    setupDrawing();

}

float TOUCH_TOLERANCE = 4;
float mX, mY;
//drawing path
private Path drawPath, drawX, drawY;
//drawing and canvas paint
private Paint drawPaint;
private Paint canvasPaint;
private View canvasback;
private Paint bccanvas;
//initial color
private int paintColor = 0xFF000000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap, trans;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();'

设置绘图

'private void setupDrawing() {
    drawPath = new Path();
    drawPaint = new Paint();
    bccanvas = new Paint();
    drawPaint.setColor(paintColor);
    drawPaint.setAntiAlias(true);
    drawPaint.setStrokeWidth(20);
    drawPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    drawPaint.setStrokeJoin(Paint.Join.ROUND);
    drawPaint.setStrokeCap(Paint.Cap.ROUND);
    canvasPaint = new Paint(Paint.DITHER_FLAG);

}'

onSizeChanged

'@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {

    super.onSizeChanged(w, h, oldw, oldh);
    canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    drawCanvas = new Canvas(canvasBitmap);

}'

触摸事件

'private void touch_start(float x, float y) {
    undonePaths.clear();
    drawPath.reset();
    drawPath.moveTo(x, y);

    mX = x;
    mY = y;
}

private void touch_move(float x, float y) {
    float dx, dy;
    dx = Math.abs(x - mX);
    dy = Math.abs(y - mY);
    if ((dx >= TOUCH_TOLERANCE) || (dy >= TOUCH_TOLERANCE)) {
        drawPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
        drawPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
        drawPath.lineTo(mX, mY);
        // commit the path to our offscreen
        drawCanvas.drawPath(drawPath, drawPaint);
        drawPath.reset();
        drawPath.moveTo(mX, mY);


        mX = x;
        mY = y;
    }
}

private void touch_up() {
    drawPath.reset();

}'

onTouchEvent

'public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();
    float y = event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:

            touch_start(x, y);
            drawPath.moveTo(x, y);

            break;
        case MotionEvent.ACTION_MOVE:

            touch_move(x, y);
            drawPath.lineTo(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            drawPath.reset();
            touch_up();

            invalidate();
            break;
    }
    return true;
}'

onDraw

'@SuppressLint("NewApi")
@Override
protected void onDraw(Canvas canvas) {

        canvas.drawPath(p, drawPaint);
        canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
    }'

onClickUndo

'public void onClickUndo () {
        if (paths.size()>0){

        undonePaths.add(paths.remove(paths.size()-1));
        invalidate();
        undonePaths.clear();
    }
    else
    {

    }
    //toast the user
}'

点击重做

'public void onClickRedo (){
    if (undonePaths.size()>0)
    {
        paths.add(undonePaths.remove(undonePaths.size()-1));
        invalidate();
    }
    else
    {

    }
    //toast the user
}'

【问题讨论】:

    标签: java android eclipse draw undo-redo


    【解决方案1】:

    TL;DR.

    几个月前,我在 Java Swing 中创建了一个类似的应用程序。我实现这两种方法的方式是我创建了一个形状堆栈,当用户向白板添加形状时添加到该堆栈中,然后从中推送/弹出以撤消/重做(将已删除的形状存储在临时变量中)

    protected Shape removed; //shape object of an undo-ed object
    protected Stack<Shape> shapes = new Stack<Shape>(); //stack to store the shapes
    
    public void undo() 
    {
        if (!shapes.empty()) //only undo if there's shapes on the board
        {
            removed = shapes.pop(); //pop removes a shape and returns it into 'removed' object
            repaint();
        }
    }
    
    public void redo() 
    {
        if (removed != null)  //only redo if something has been undone
        {
            shapes.push(removed); //push adds the object back onto the stack
            removed = null;
            repaint();
        }
    }
    

    我希望这会有所帮助!

    【讨论】:

    • 我试过但没有成功。随便我必须在 OnDraw、OnTouchEvent、Touch Event 或 OnSizeChanged 中添加一些东西??
    • 您需要将形状存储在某个地方,以便您可以撤消/重做它们。我建议您在放置点时创建 2D 形状的实例。或者,您可以撤消并重做您正在绘制的顶点,但您需要再次存储一堆顶点,以便您知道哪个是最后一个放置用于撤消的顶点。您可以实现 2 个堆栈,一个用于绘制的顶点,一个用于未完成的顶点。您可以在撤消时将已绘制堆栈中的顶点弹出到撤消堆栈中,然后以相反的方式重做。
    • 更新:快速浏览一下您的代码,您似乎正在存储路径。将您的路径数组列表转换为堆栈,您可以在撤消/重做时推送/弹出它们。确保您的paint方法只绘制路径堆栈而不是undoPaths
    【解决方案2】:

    一个好的方法是创建一个名为“Undoable”之类的接口。它至少有 3 个覆盖:do()、undo() 和 redo()。然后在实现 Undoable 的类中完成所有工作,并在周围保留一堆这些 = 撤消历史记录。

    【讨论】:

    • 这是我的第一个应用程序,所以我不太明白我应该做什么。您可以发布活动的代码吗?
    猜你喜欢
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 2013-03-31
    • 2013-08-20
    • 2015-03-30
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    相关资源
    最近更新 更多