Click here to Skip to main content
15,886,258 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have subclassed CEditEx from CEdit, so when overriding the base class CWnd::OnChar, on the subclassed CEditEx class (CEditEx::OnChar), the function CEditEx::Undo will have no effect (lost), but the functions: CEditEx::Cut, CEditEx::Copy and CEditEx::Paste are functional.
I have found that the definition of CEdit::Undo function is as folows:
_AFXWIN_INLINE BOOL CEdit::Undo()
	{ ASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, EM_UNDO, 0, 0); }


Unfortunately, it is not debugable. And because of that I need to rewrite the CEditEx::Undo function.

Can anyone give me an algorithm of that function

Thank you for your understand.

Update:
This is my CEditEx::OnChar function:
C#
void CEditEx::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    // TODO: Add your message handler code here and/or call default
    if (nChar == VK_BACK)
        return;

    if (!_istdigit(nChar))
    {
        ::MessageBeep((UINT)-1);

        return;
    }

    CString strWindowText;
    int nStartChar, nEndChar;

    GetWindowText(strWindowText);
    GetSel(nStartChar, nEndChar);

    if (nStartChar != nEndChar)
        strWindowText.Delete(nStartChar, nEndChar - nStartChar);
    else
        ValidateWindowText(strWindowText, nStartChar, TRUE);

    strWindowText.Insert(nStartChar ++, nChar);
    ValidateWindowText(strWindowText, nStartChar);
    nEndChar = nStartChar;
    //GetWindowText(m_strWindowTextUndo);
    SetWindowText(strWindowText);
    SetSel(nStartChar, nEndChar);
    //SetModify();

    //CEdit::OnChar(nChar, nRepCnt, nFlags);
}
Posted
Updated 3-Feb-12 3:08am
v3

1 solution

If you are calling CEdit::OnChar() from your CEditEx::OnChar(), the default Undo should still work.

Because the default Undo of an edit control can only undo the last operation, implementation is simple: In CEditEx::OnChar() store the text in an undo member variable when the content is to be changed (e.g. when not handling a cursor key). In your CEditEx::Undo() restore the content by passing the text from the undo member variable to SetWindowText().

To support undo for copy, cut, and paste operations, copy the text to the same variable in these handlers.

Updated answer for the updated question:
Add these to your class:
C++
class CEditEx : public CEdit
{
...
public:
    inline BOOL CanUndo() const { return m_bCanUndo; }
protected:
    void SaveUndoText();
    BOOL m_bCanUndo;
    CString m_strWindowTextUndo;
...
public:
    afx_msg void OnCut();	
    afx_msg void OnUndo();
}

And these to your implementation:
C++
CEditEx::CEditEx()
{
    m_bCanUndo = FALSE;
}

BEGIN_MESSAGE_MAP(CEditEx, CEdit)
...
    ON_COMMAND(ID_EDIT_CUT, OnCut)
    ON_COMMAND(ID_EDIT_UNDO, OnUndo)
END_MESSAGE_MAP

void CEditEx::SaveUndoText()
{
    GetWindowText(m_strWindowTextUndo);
    m_bCanUndo = TRUE;
}

void CEditEx::OnUndo()
{
    if (m_bCanUndo)
    {
        CString strRedo;
        GetWindowText(strRedo);
        SetWindowText(m_strWindowTextUndo);
        m_strWindowTextUndo = strRedo;
    }
}

void CEditEx::OnCut()
{
    // Must check for selection. Otherwise undo would not work.
    int nStartChar, nEndChar;
    GetSel(nStartChar, nEndChar);
    if (nStartChar != nEndChar)
    {
        SaveUndoText();
        CEdit::Cut();
    }
}

void CEditEx::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
...
    // Before changing the content.
    SaveUndoText();
...
}

Implement OnClear() and OnPaste() like OnCut().
 
Share this answer
 
v2
Comments
Mr. Tomay 3-Feb-12 10:15am    
I have updated my question (I have added CEditEx::OnChar function implementation) to make it easy to understand. And also I have found that The undo flag is automatically cleared whenever the SetWindowText or SetHandle CWnd member functions are called.
See the Remarks section in this page: http://msdn.microsoft.com/en-us/library/xkttez3x.aspx[^]
Jochen Arndt 3-Feb-12 10:20am    
See my updated answer. It uses its own undo implementation with its own undo state member variable. However, it has not been tested. I have just written it from scratch.
Mr. Tomay 3-Feb-12 16:04pm    
It seems functional, but:

To re-implement the default Undo function of an edit control, you need to select some text after the Undo operation SetSel (You will see that if you try to play with a default edit control by undoing), also handling EM_CANUNDO, EM_GETMODIFY, EM_SETMODIFY, EM_EMPTYUNDOBUFFER and EM_UNDO is better than overriding respectively the base class function: CanUndo(), GetModify(), SetModify(), EmptyUndoBuffer() and Undo(), because if for example the user has to undo the text, he will have two options:
the Undo function Undo() or by sending a message (SendMessage(EM_UNDO, 0, 0);).
By the way Undo() will call SendMessage(EM_UNDO, 0, 0);.
Jochen Arndt 5-Feb-12 5:14am    
You are right for the most part.

But the user can not call the handler functions. He can call the undo option from the edit menu or press Ctrl+Z. Both will send an ID_EDIT_UNDO message. If this message is handled by your class without calling the default Undo() or sending EM_UNDO, the default undo implementation is simply not used and you don't have to care about.
Mr. Tomay 6-Feb-12 13:30pm    
Assuming the user will never call Undo(); or SendMessage(EM_UNDO, 0, 0);, so handling only the ID_EDIT_UNDO message will do the job.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900