高手解答:關(guān)于RICHEDIT的兩個問題

字號:

問題1:RichEditCtrl在用DDX進行數(shù)據(jù)交換的時候會發(fā)生數(shù)據(jù)丟失問題?為什么!
    當(dāng)我們在拖了一個控件到程序里后,通常的做發(fā)是Ctrl+W,用類向?qū)Ыo控件關(guān)聯(lián)一個變量,然后依靠DDX/DDV進行數(shù)據(jù)交換,如果我們用同樣的方法來給RICHEDIT關(guān)聯(lián)一個CString類型的變量就會存在一個問題,就是如果我們的數(shù)據(jù)大于了64K,數(shù)據(jù)就會丟失。
    通過查MSDN發(fā)現(xiàn),WM_GETTEXT消息并沒有設(shè)計在RICHEDIT的數(shù)據(jù)大于64K的時候怎樣處理。而類向?qū)傻拇a是用DDX_Text來交換控件和CString變量的數(shù)據(jù)。恰好,DDX_Text函數(shù)是調(diào)用GetWindowText函數(shù),而這個函數(shù)又會發(fā)出WM_GETTEXT消息到控件來返回控件里的數(shù)據(jù)。WM_GETTEXT消息不能接受超過64K的數(shù)據(jù),因此導(dǎo)致了RICHEDIT在數(shù)據(jù)交換的時候發(fā)生了丟失。
    為了解決這個問題,我們要用到DDX_RichText函數(shù)。添加下面兩個函數(shù)到工程
    以下是引用片段:
    DWORD CALLBACK ES2MemCallBack(DWORD_PTR dwCookie,LPBYTE pbBuff, LONG cb, LONG *pcb)
    {
    LPTSTR& lpszStrFill = *(LPTSTR*)dwCookie;
    memcpy(lpszStrFill, pbBuff, *pcb = cb);
    lpszStrFill += cb;
    *lpszStrFill = TCHAR('\0');
    return 0;
    }
    void AFXAPI DDX_RichText(CDataExchange* pDX, int nIDC, CString& value)
    {
    extern void AFXAPI AfxSetWindowText(HWND hWndCtrl, LPCTSTR lpszNew);
    HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
    if (pDX->m_bSaveAndValidate)
    {
    int nLen = ::GetWindowTextLength(hWndCtrl);
    LPTSTR lpszStrFill = value.GetBufferSetLength(nLen);
    EDITSTREAM es = { (DWORD_PTR) &lpszStrFill, 0, ES2MemCallBack };
    ::SendMessage(hWndCtrl, EM_STREAMOUT, SF_TEXT, (LPARAM) &es);
    value.ReleaseBuffer();
    }
    else
    {
    AfxSetWindowText(hWndCtrl, value);
    }
    }
    之后我們還需要修改工程的.clw文件,用文本方式打開.clw文件。參考里面類的格式加下面兩行代碼:
    以下是引用片段:
    ExtraDDXCount=1
    ExtraDDX1=7;;TextOver64KB;CString;;RichText;Retrieves text in excess of 64KB from RichEdit controls
    如果沒有采用上面的步驟,我們就需要手動修改代碼,把所有的DDX_Text改為DDX_RichText。同時要把他們移到類向?qū)Э刂拼a的外面。也就是移出:
    以下是引用片段:
    //{{AFX_DATA_INIT(...)
    //}}AFX_DATA_INIT
    //{{AFX_DATA_MAP(...)
    //}}AFX_DATA_MAP
    reference:
    Q280447 BUG: Text from a Rich Edit Control Is Truncated During Dialog Data Exchange (DDX)
    問題2:當(dāng)我們用類向?qū)Ыorichedit添加了EN_SETFOCUS, EN_KILLFOCUS的函數(shù)后卻不能響應(yīng),我發(fā)現(xiàn)這個響應(yīng)函數(shù)根本就沒有被調(diào)用。即使是一個MessageBox()函數(shù)也不會調(diào)用。
    原來是默認的消息映射添加錯誤了。
    正確的消息影射和響應(yīng)應(yīng)該是:
    以下是引用片段:
    ON_EN_SETFOCUS(IDC_RICHEDIT1,OnSetfocusRichedit1)
    ON_EN_KILLFOCUS(IDC_RICHEDIT1,OnKillfocusRichedit1)
    響應(yīng)函數(shù)形式為:
    以下是引用片段:
    afx_msg void OnSetfocusRichedit1();
    afx_msg void OnKillfocusRichedit1();
    但是如果我們用類向?qū)碇苯犹砑樱傻拇a卻是:
    以下是引用片段:
    ON_NOTIFY(EN_SETFOCUS, IDC_RICHEDIT1, OnSetfocusRichedit1)
    ON_NOTIFY(EN_KILLFOCUS, IDC_RICHEDIT1, OnKillfocusRichedit1)
    我們需要自己手動改為上面的形式。
    還有一個問題就是RichEditCtrl有時候不會出現(xiàn)在類向?qū)У目丶蘒D列表里。這就需要我們自己添加DDX/DDV函數(shù)。自己動手啦!^_^
    以下是引用片段:
    -- sampledlg.h --
    class CSampleDlg : public CDialog
    {
    public:
    CSampleDlg(CWnd* pParent = NULL);
    // Dialog Data
    //{{AFX_DATA(CSampleDlg)
    enum { IDD = IDD_SAMPLE_DIALOG };
    CString m_edit; // Added by ClassWizard for an edit control
    //}}AFX_DATA
    // Manually add member variables for the rich edit control
    CRichEditCtrl m_richEditCtrl;
    .......
    sampledlg.cpp --
    ......
    void CSampleDlg::DoDataExchange(CDataExchange* pDX)
    {
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CSampleDlg)
    DDX_Text(pDX, IDC_EDIT, m_edit);
    DDV_MaxChars(pDX, m_edit, 10);
    //}}AFX_DATA_MAP
    // Manually add DDX_Control, DDX_Text and DDV_MaxChars for the
    // rich edit control
    DDX_Control(pDX, IDC_RICHEDIT1, m_richEditCtrl);
    DDX_Text(pDX, IDC_RICHEDIT1, m_richedit);
    DDV_MaxChars(pDX, m_richedit, 10);
    }