• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 多步Undo/Redo的實現

    發表于:2007-07-14來源:作者:點擊數: 標簽:
    首先,建立一個基類CEditRecord,對于每一種操作,都從該基類上派生出與操作相對應的類,記載操作過程,供以后進行具體的Undo/Redo操作;基類CEditRecord中的純虛函數,為Undo、Redo操作提供接口。 然后,建立一個用于控制Undo/Redo的類:CRecordCtrl。 CReco
        首先,建立一個基類CEditRecord,對于每一種操作,都從該基類上派生出與操作相對應的類,記載操作過程,供以后進行具體的Undo/Redo操作;基類CEditRecord中的純虛函數,為Undo、Redo操作提供接口。

        然后,建立一個用于控制Undo/Redo的類:CRecordCtrl。 CRecordCtrl類從基類CObArray上派生,用于記載已經進行過的操作,響應Undo/Redo命令等;其中nMaxStep變量表示允許Undo/Redo的次數,nCurrRecord變量表示當前的Undo的位置;函數Undo()和Redo()用于響應來自系統菜單、快捷鍵或者工具條的Undo和Redo命令;函數SetMaxStep()用于設置允許Undo/Redo的次數。

    ////////////////////////////////////////////////////////
    // CEditRecord.h
    // Class CEditRecord、CEditCtrl Definition
    class CEditRecord : public CObject
    {
    public:
    CEditRecord();
    public:
    virtual BOOL Undo( )=0;
    virtual BOOL Redo( )=0;
    };

    class CRecordCtrl:public CObArray
    {
    public:
    CRecordCtrl( );
    ~CRecordCtrl( );
    private:
    int nCurrRecord;
    int nMaxStep;
    public:
    BOOL EnableUndo( );
    BOOL EnableRedo( );
    BOOL Undo( );
    BOOL Redo( );
    BOOL SetMaxStep(int n);
    };

    extern CEditCtrl Records;


    ////////////////////////////////////////////////////
    // CEditRecord.Cpp
    // Class CEdit、CEditCtrl Imeplemetion

    #include "CEditRecord.h"
    CRecordCtrl Records;

    CEditRecord::CEditRecord( )
    {
    int mm=Records.GetSize( );
    if(nCurrRecord==mm-1)
    {
    if(mm==nMaxStep)
    {
    //刪除最早的記錄
    CEditRecord* pRec=(CEditRecord*)GetAt(0);
    delete pRec;
    Records.RemoveAt(0);
    nCurrRecord--;
    }
    }
    else
    {
    //刪除所有Undo過的記錄
    for(int i=mm-1;i>nCurrRecord;i--)
    {
    CEditRecord* pRec=(CEditRecord*)GetAt(i);
    delete pRec;
    Records.RemoveAt(i);
    }
    }

    nCurrRecord=Records.Add(this);
    }

    CRecordCtrl::CRecordCtrl( )
    {
    nCurrRecord=-1;
    nMaxStep=5;
    }

    CRecordCtrl::~CRecordCtrl( )
    {
    for(int i=GetSize()-1;i>=0;i--)
    {
    CEditRecord* pUndo=(CEditRecord*)GetAt(i);
    delete pUndo;
    }
    }

    BOOL CRecordCtrl::EnableUndo( )
    {
    return (nCurrRecord>=0);
    }

    BOOL CRecordCtrl::EnableRedo( )
    {
    return (nCurrRecord<GetSize( )-1);
    }

    BOOL CRecordCtrl::Undo( )
    {
    if(!EnableUndo( )) return FALSE;

    CEditRecord* pRec=(CEditRecord*)GetAt(nCurrRecord--);
    if(pRec==NULL) return FALSE;

    return pRec->Undo();
    }

    BOOL CRecordCtrl::Redo()
    {
    if(!EnableRedo( )) return FALSE;

    CEditRecord* pRec=(CEditRecord*)GetAt(++nCurrRecord);
    if(pRec==NULL) return FALSE;

    return pRec->Redo();
    }


    BOOL CRecordCtrl::SetMaxStep(int n)
    {
    if(n<1) return FALSE;
    int mm=GetSize( );

    if(UndoStep<=n || mm<=n)
    {
    UndoStep=n;
    return TRUE;
    }
    else
    {
    //壓縮用于Undo的記錄
    int nPack=mm-n;
    int u=min(nCurrRecord,nPack);
    for(int i=u-1;i>=0;i--)
    {
    CEditRecord* pRec=(CEditRecord*)GetAt(i);
    delete pRec;
    nCurrRecord--;
    }

    //壓縮用于Redo的記錄
    int v=nPack-u;
    for(int i=0;i<v;i++)
    {
    CEditRecord* pRec=(CEditRecord*)GetAt(mm-i-1);
    if(pRedo==NULL) delete pRec;
    }
    }
    return TRUE;
    }
    在CEditRecord的生成函數中,首先判定是否達到允許的最大Undo次數; 如果未達到,直接把this指針加入到陣列中;如果超過,需要從陣列中,清除一些關于早期的操作的記錄,然后把this指針加入到陣列中。

    函數CRecordCtrl::SetMaxStep( )中,對于縮小Undo/Redo次數這種情況,特別是在陣列中已經記載了較多的操作,則需清除一些。

    在CRecordCtrl類的析構函數中,清除陣列中的每一個CEditRecord對象。

    下面給出一個例子說明如何建立CEditRecord對象,為方便計,假設進行的操作是從一個全局性的字符串pText中刪除一段內容,我們用Pos表示所刪內容在pText中的相對位置, 用Len表示所刪內容的長度,并假設全局串pTetx的存儲空間足夠大。

    1.從基類CEditRecord上派生出CEditCutString;
    2.設置私有變量Pos、Len用于表示所刪內容在pText中的相對位置、長度;設置私有變量pBuff用于分配存儲空間,保存所刪內容;設置私有變量Avialiable用于表示可否進行Undo/Redo。

    /////////////////////////////////////////////////////
    // Example
    //
    #include "CEditRecord.h"

    class CEditCutString:public CEditRecord
    {
    public:
    CEditCutString(int,int);
    ~CEditCutString();
    private:
    int Pos;
    int Len;
    char* pBuff;
    BOOL Avialiable;

    public:
    virtual BOOL Undo();
    virtual BOOL Redo();
    };


    CEditCutString::CEditCutString(int p,int n)
    {
    Pos=p;
    Len=n;
    pBuff=new char[n];

    if(pBuff==NULL)
    Avialiable=FALSE;
    esle
    {
    Avialiable=TRUE;
    memcpy(pBuff,pText+Pos,Len);
    }
    }

    CEditCutString::~CEditCutString
    {
    if(Avialiable)
    delete []pBuff;
    }

    BOOL CEditCutString::Undo()
    {
    if(!Avialiable)
    return FALSE;

    int l=strlen(pText);
    for(int i=l;i>=Pos;i--)
    pText[i+Len]=pText[i];

    for(int j=0;j<Len;j++)
    pText[Pos+j]=pBuff[j];

    return TRUE;
    }

    BOOL CEditCutString::Redo()
    {
    if(!Avialiable)
    return FALSE;

    int l=strlen(pText);

    for(int i=Pos;i<=l-Len;i++)
    pText[i]=pText[i+Len];

    return TRUE;
    }

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>