• 关于RICHEDIT的两个问题


    问题1:
          RichEditCtrl在用DDX进行数据交换的时候会发生数据丢失问题?为什么!
          当我们在拖了一个控件到程序里后,通常的做发是Ctrl+W,用类向导给控件关联一个变量,然后依靠DDX/DDV进行数据交换,如果我们用同样的方法来给RICHEDIT关联一个CString类型的变量就会存在一个问题,就是如果我们的数据大于了64K,数据就会丢失。
         通过查MSDN发现,WM_GETTEXT消息并没有设计在RICHEDIT的数据大于64K的时候怎样处理。而类向导生成的代码是用DDX_Text来交换控件和CString变量的数据。恰好,DDX_Text函数是调用GetWindowText函数,而这个函数又会发出WM_GETTEXT消息到控件来返回控件里的数据。WM_GETTEXT消息不能接受超过64K的数据,因此导致了RICHEDIT在数据交换的时候发生了丢失。
        为了解决这个问题,我们要用到DDX_RichText函数。添加下面两个函数到工程
    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。同时要把他们移到类向导控制代码的外面。也就是移出:
    //{{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:
            当我们用类向导给richedit添加了EN_SETFOCUS, EN_KILLFOCUS的函数后却不能响应,我发现这个响应函数根本就没有被调用。即使是一个MessageBox()函数也不会调用。
    原来是默认的消息映射添加错误了。
    正确的消息影射和响应应该是:
    ON_EN_SETFOCUS(IDC_RICHEDIT1,OnSetfocusRichedit1)
    ON_EN_KILLFOCUS(IDC_RICHEDIT1,OnKillfocusRichedit1)
    响应函数形式为:
    afx_msg void OnSetfocusRichedit1();
    afx_msg void OnKillfocusRichedit1();

    但是如果我们用类向导来直接添加,生成的代码却是:
    ON_NOTIFY(EN_SETFOCUS, IDC_RICHEDIT1, OnSetfocusRichedit1)
    ON_NOTIFY(EN_KILLFOCUS, IDC_RICHEDIT1, OnKillfocusRichedit1)
    我们需要自己手动改为上面的形式。

    还有一个问题就是RichEditCtrl有时候不会出现在类向导的控件ID列表里。这就需要我们自己添加DDX/DDV函数。自己动手啦!^_^
    -- sampledlg.h --
    class CSampleDlg : public CDialog
    {
       public:
          CSampleDlg(CWnd* pParent = NULL);

       // Dialog Data
          //{{AFX_DATA(CSampleDlg)
          enum { IDD = IDD_SAMPLE_DIALOG };
          CString  m_edit;      // 类向导为EDIT空间生成的变量
          //}}AFX_DATA

       //俺们自己给RICHEDIT加个
          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
       // 再手动为RICHEDIT添加函数DDX_Control, DDX_Text and DDV_MaxChars 
          DDX_Control(pDX, IDC_RICHEDIT1, m_richEditCtrl);
          DDX_Text(pDX, IDC_RICHEDIT1, m_richedit);
          DDV_MaxChars(pDX, m_richedit, 10);
    }

    reference:
    Q181664

  • 相关阅读:
    3.24
    3.23
    构建之法读书笔记2
    寒假学习day23
    寒假学习day22
    寒假学习day21
    寒假学习day20
    寒假学习day19
    寒假学习每周总结4
    寒假学习day18
  • 原文地址:https://www.cnblogs.com/hehe520/p/6330155.html
Copyright © 2020-2023  润新知