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

字號(hào):

問(wèn)題1:RichEditCtrl在用DDX進(jìn)行數(shù)據(jù)交換的時(shí)候會(huì)發(fā)生數(shù)據(jù)丟失問(wèn)題?為什么!
    當(dāng)我們?cè)谕狭艘粋€(gè)控件到程序里后,通常的做發(fā)是Ctrl+W,用類(lèi)向?qū)Ыo控件關(guān)聯(lián)一個(gè)變量,然后依靠DDX/DDV進(jìn)行數(shù)據(jù)交換,如果我們用同樣的方法來(lái)給RICHEDIT關(guān)聯(lián)一個(gè)CString類(lèi)型的變量就會(huì)存在一個(gè)問(wèn)題,就是如果我們的數(shù)據(jù)大于了64K,數(shù)據(jù)就會(huì)丟失。
    通過(guò)查MSDN發(fā)現(xiàn),WM_GETTEXT消息并沒(méi)有設(shè)計(jì)在RICHEDIT的數(shù)據(jù)大于64K的時(shí)候怎樣處理。而類(lèi)向?qū)傻拇a是用DDX_Text來(lái)交換控件和CString變量的數(shù)據(jù)。恰好,DDX_Text函數(shù)是調(diào)用GetWindowText函數(shù),而這個(gè)函數(shù)又會(huì)發(fā)出WM_GETTEXT消息到控件來(lái)返回控件里的數(shù)據(jù)。WM_GETTEXT消息不能接受超過(guò)64K的數(shù)據(jù),因此導(dǎo)致了RICHEDIT在數(shù)據(jù)交換的時(shí)候發(fā)生了丟失。
    為了解決這個(gè)問(wèn)題,我們要用到DDX_RichText函數(shù)。添加下面兩個(gè)函數(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文件,用文本方式打開(kāi).clw文件。參考里面類(lèi)的格式加下面兩行代碼:
    以下是引用片段:
    ExtraDDXCount=1
    ExtraDDX1=7;;TextOver64KB;CString;;RichText;Retrieves text in excess of 64KB from RichEdit controls
    如果沒(méi)有采用上面的步驟,我們就需要手動(dòng)修改代碼,把所有的DDX_Text改為DDX_RichText。同時(shí)要把他們移到類(lèi)向?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)
    問(wèn)題2:當(dāng)我們用類(lèi)向?qū)Ыorichedit添加了EN_SETFOCUS, EN_KILLFOCUS的函數(shù)后卻不能響應(yīng),我發(fā)現(xiàn)這個(gè)響應(yīng)函數(shù)根本就沒(méi)有被調(diào)用。即使是一個(gè)MessageBox()函數(shù)也不會(huì)調(diào)用。
    原來(lái)是默認(rèn)的消息映射添加錯(cuò)誤了。
    正確的消息影射和響應(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();
    但是如果我們用類(lèi)向?qū)?lái)直接添加,生成的代碼卻是:
    以下是引用片段:
    ON_NOTIFY(EN_SETFOCUS, IDC_RICHEDIT1, OnSetfocusRichedit1)
    ON_NOTIFY(EN_KILLFOCUS, IDC_RICHEDIT1, OnKillfocusRichedit1)
    我們需要自己手動(dòng)改為上面的形式。
    還有一個(gè)問(wèn)題就是RichEditCtrl有時(shí)候不會(huì)出現(xiàn)在類(lèi)向?qū)У目丶蘒D列表里。這就需要我們自己添加DDX/DDV函數(shù)。自己動(dòng)手啦!^_^
    以下是引用片段:
    -- 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);
    }