CRichEditCtrl 超文本編輯 常見問題

來源:互聯網
上載者:User
CRichEditCtrl 超文本編輯

一.常見問題
a.可以編譯,不能執行的

AfxInitRichEdit();

b.升級預設的Riched版本(預設的有一些bug)
可在InitInstance中添加
LoadLibrary("RICHED20.DLL")
最後注意 FreeLibrary

如果是CRichEditView基類的可用
BOOL CXXXXXXView::PreCreateWindow(CREATESTRUCT& cs)
{
//裝入rich edit version 2.0
    if (LoadLibraryA("RICHED20.DLL") == NULL)
    {
        AfxMessageBox(_T("Fail to load /"riched20.dll/"."),MB_OK | MB_ICONERROR);
        PostMessage(WM_QUIT,0,0);
        return FALSE;
    }

    m_str 2.0 class

    return CRichEditView::PreCreateWindow(cs);
}

c.最後追加行
richeditctrl.SetSel(-1, -1);
richeditctrl.ReplaceSel( (LPCTSTR)str );

d.字數限制
CRichEditCtrl::LimitText(long nChars)

e.換行切換
CRichEditView的OnInitialUpdate()函數中加入下面兩句:
m_nWordWrap = WrapNone;
WrapChanged();
WrapChanged實際上也是調用
ctrl.SetTargetDevice(NULL, 1); //m_nWordWrap == WrapNone
ctrl.SetTargetDevice(NULL, 0); //m_nWordWrap == WrapToWindow
還有不常用的 m_nWordWrap == WrapToTargetDevice
ctrl.SetTargetDevice(m_dcTarget, GetPrintWidth());
如果是在Dialog中,可使用SetTargetDevice,注意在屬性裡面加上want return

f.有時候不希望帶格式的資料粘貼,可通過PasteSpecial選擇性粘貼
pmyRichEditCtrl->PasteSpecial(CF_TEXT);

g.隨著輸入隨著自動捲軸滾動到最後一行
int nFirstVisible = pmyRichEditCtrl->GetFirstVisibleLine();
if (nFirstVisible > 0)
{
   pmyRichEditCtrl->LineScroll(-nFirstVisible, 0);
}

m_cRichEdit.PostMessage(WM_VSCROLL, SB_BOTTOM,0);

h.設定UNDO的次數(只能用在RICHED20以上,即預設不支援,必須升級)
SendMessage(EM_SETTEXTMODE,TM_MULTILEVELUNDO,0);
TM_MULTILEVELUNDO 支援多取消(預設值).可通過EM_SETUNDOLIMIT設定最大次數
SendMessage(EM_SETUNDOLIMIT,100,0);

i.響應OnChange
EM_SETEVENTMASK 設定 ENM_CHANGE
long lMask = GetEventMask();
lMask |= ENM_CHANGE;
lMask &= ~ENM_PROTECTED;
SetEventMask(lMask);

j.設定唯讀
CRichEditCtrl::SetReadOnly( BOOL bReadOnly = TRUE );
通過設定PROTECTED實現選中的文本唯讀,參見
http://www.codeguru.com/Cpp/controls/richedit/article.php/c2401/

 

二.函數應用
a.設定字型(主要是通過SetSelectionCharFormat)

CHARFORMAT cf;
ZeroMemory(&cf, sizeof(CHARFORMAT));
cf.cbSize = sizeof(CHARFORMAT);
cf.dwMask|=CFM_BOLD;
cf.dwEffects|=CFE_BOLD;//設定粗體,取消用cf.dwEffects&=~CFE_BOLD;
cf.dwMask|=CFM_ITALIC;
cf.dwEffects|=CFE_ITALIC;//設定斜體,取消用cf.dwEffects&=~CFE_ITALIC;
cf.dwMask|=CFM_UNDERLINE;
cf.dwEffects|=CFE_UNDERLINE;//設定斜體,取消用cf.dwEffects&=~CFE_UNDERLINE;
cf.dwMask|=CFM_COLOR;
cf.crTextColor = RGB(255,0,0);//設定顏色
cf.dwMask|=CFM_SIZE;
cf.yHeight =200;//設定高度
cf.dwMask|=CFM_FACE;
strcpy(cf.szFaceName ,_T("隸書"));//設定字型
rich.SetSelectionCharFormat(cf);

b.設定字型的行間距
要用richedit2.0以上
試試
PARAFORMAT2 pf;
pf.cbSize = sizeof(PARAFORMAT2);
pf.dwMask = PFM_NUMBERING | PFM_OFFSET;
pf.wNumbering = PFN_BULLET;//注意PFM_NUMBERING
pf.dxOffset = 10;
VERIFY(SetParaFormat(pf));
常用的dwMask有
PFM_NUMBERING 成員 wNumbering 才起作用,項目符號,預設用PFN_BULLET
2 使用阿拉伯數字 (1, 2, 3, ...).
3 使用小寫字母 (a, b, c, ...).
4 使用大寫字母 (A, B, C, ...).
5 使用小寫羅馬數字 (i, ii, iii, ...).
6 使用大寫羅馬數字 (I, II, III, ...).
7 自訂,字元見成員 wNumberingStart.
PFM_OFFSET 成員 dxOffset 才起作用,縮排,單位twips
PFM_STARTINDENT 成員 dxStartIndent 才起作用,首行縮排
PFM_SPACEAFTER 成員 dySpaceAfter 才起作用,段間距
PFM_LINESPACING 成員 dyLineSpacing 才起作用,行間距

c.設定CRichEditCtrl(2.0)背景透明
long style = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
style &= WS_EX_TRANSPARENT;
::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, style);
或 CreateEx,然後把WS_EX_TRANSPARENT樣式加上

e.得到內容有三種
1)GetWindowText
2)使用EM_GETTEXTEX
GETTEXTEX gt;
gt.cb = 200;
gt.flags = GT_DEFAULT;
gt.codepage = CP_ACP ;
gt.lpDefaultChar = NULL;
gt.lpUsedDefChar = NULL;
SendMessage(EM_GETTEXTEX,(WPARAM)>,(LPARAM)text);
3)StreamOut(主要用於RTF等格式輸出)
static DWORD CALLBACK
    MyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
   CFile* pFile = (CFile*) dwCookie;

   pFile->Write(pbBuff, cb);
   *pcb = cb;

   return 0;
}

   CFile cFile(TEXT("myfile.rtf"), CFile::modeCreate|CFile::modeWrite);
   EDITSTREAM es;
   es.dwCookie = (DWORD) &cFile;//設定用例參數,以便回呼函數調用
   es.pfnCallback = MyStreamOutCallback;
   pmyRichEditCtrl->StreamOut(SF_RTF, es);
讀入可以此類推,SetWindowText,EM_SETTEXTEX,StreamIn

f.尋找字串
FINDTEXTEX ft;
ft.chrg.cpMin = 0;
ft.chrg.cpMax = -1;
ft.lpstrText = "|";
long lPos = FindText(0, &ft);

如果要繼續尋找,修改cpMin,如
int nCount = 0;
do
{
long lPos = GetRichEditCtrl().FindText(0, &ft);
if( -1 == lPos) break;
ft.chrg.cpMin = lPos + strlen(ft.lpstrText);
++nCount;
}while(TRUE);

g.以Html格式儲存
目前做法可先轉為RTF格式,再通過RTF-to-HTML Converter
http://www.codeguru.com/Cpp/controls/richedit/conversions/article.php/c5377/

h.重載OnProtected函數得到對應的訊息,如粘貼等
void CMYichEditorView::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)
{
    ENPROTECTED* pEP = (ENPROTECTED*)pNMHDR;

    switch (pEP->msg)

    {
        case WM_KEYDOWN://按鍵,判斷pEP->wParam
        case WM_PASTE://粘貼
        case WM_CUT://剪下
        case EM_SETCHARFORMAT:
       default:
             break;
    };

   *pResult = FALSE;
}

 

三.聊天常用
a.LINK 連結功能

步驟:

 1. 建立基於對話方塊的mfc工程,名字就叫showlink吧。

 2. 將richedit控制項拖入對話方塊內,開啟CShowlinkApp類,在InitInstance中添加AfxInitRichEdit()。

 3. 用classwizard建立一個CRichEditCtrl的衍生類別CMyEdit,並添加兩個函數:

void CMyEdit::SetLink()
{
  CHARFORMAT2   cf2;  
  ZeroMemory(&cf2,   sizeof(CHARFORMAT2));//  
  cf2.cbSize   =   sizeof(CHARFORMAT2);  
  cf2.dwMask   =   CFM_LINK;  
   
  cf2.dwEffects   |=   CFE_LINK;  
  SendMessage(EM_SETCHARFORMAT,   SCF_SELECTION,   (LPARAM)&cf2);  

}

void CMyEdit::OnURLClick(NMHDR *pNmhdr, LRESULT *pResult)
{
 TCHAR   LinkChar[512];  
 ENLINK   *penLink   =   (ENLINK   *)pNmhdr;  
 if   (penLink->msg   ==   WM_LBUTTONUP)  
 {  
  SetSel(penLink->chrg);  
  long   Res   =   GetSelText((char   *)LinkChar);  
  LinkChar[Res]   =   0;   
  ShellExecute(NULL, "open", LinkChar, NULL, NULL, SW_SHOWNORMAL);  
  }  
  pResult   =   FALSE;  

}

4.在MyEdit.cpp的BEGIN_MESSAGE_MAP(CMyEdit, CRichEditCtrl)裡添加一句話:ON_NOTIFY_REFLECT(EN_LINK,OnURLClick)

5.在showlinkdlg.h中添加#include "MyEdit.h",在類中添加一個成員變數CMyedit  m_cRich.

6.在CShowlinkDlg的OnInitDialog中添加兩句:

 m_cRich.SetEventMask(ENM_LINK);
m_cRich.SendMessage(EM_AUTOURLDETECT, (WPARAM)true,0);

編譯一下,輸入個網址,點擊就可以開啟了

 

b.插入位元影像
http://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/
http://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/

自訂在RichEdit中插入對象的表徵圖
http://www.blogcn.com/user3/jiangsheng/blog/1319738.html
方法基本同Knowledge Base文章Q220844 HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control
只是在最後插入之前調用一下IOleCache::SetData,用一個HGLOBAL作為參數,HGLOBAL裡面的資料是一個METAFILEPICT結構,包含自己提供的圖片

使用CRichEditView::InsertFileAsObject就可以插入映像。VC++帶有一個例子WordPad。
另外可以參考“Insert any HBITMAP (Bitmap) in your RichEdit Control”(http://www.codeguru.com/richedit/richeditrc.html)。

c.顯示GIF動畫

//使用了QQ的影像處理控制項
#import  "ImageOle.dll" named_guids

//只能載入bmpvoid COleRichEditCtrl::InsertBitmap(HBITMAP hBitmap){STGMEDIUM stgm;stgm.tymed = TYMED_GDI;    // Storage medium = HBITMAP handlestgm.hBitmap = hBitmap;stgm.pUnkForRelease = NULL; // Use ReleaseStgMediumFORMATETC fm;fm.cfFormat = CF_BITMAP;    // Clipboard format = CF_BITMAPfm.ptd = NULL;       // Target Device = Screenfm.dwAspect = DVASPECT_CONTENT;   // Level of detail = Full contentfm.lindex = -1;       // Index = Not applicaplefm.tymed = TYMED_GDI;  ////建立輸入資料來源IStorage *pStorage; ///分配記憶體LPLOCKBYTES lpLockBytes = NULL;SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);if (sc != S_OK)AfxThrowOleException(sc);ASSERT(lpLockBytes != NULL);sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pStorage);if (sc != S_OK){VERIFY(lpLockBytes->Release() == 0);lpLockBytes = NULL;AfxThrowOleException(sc);}ASSERT(pStorage != NULL);COleDataSource *pDataSource = new COleDataSource;pDataSource->CacheData(CF_BITMAP, &stgm);LPDATAOBJECT lpDataObject = (LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);///擷取RichEdit的OLEClientSiteLPOLECLIENTSITE lpClientSite;this->GetIRichEditOle()->GetClientSite( &lpClientSite );///建立OLE對象IOleObject *pOleObject;sc = OleCreateStaticFromData(lpDataObject,IID_IOleObject,OLERENDER_FORMAT,&fm,lpClientSite,pStorage,(void **)&pOleObject);if(sc!=S_OK)AfxThrowOleException(sc);///插入OLE對象REOBJECT reobject;ZeroMemory(&reobject, sizeof(REOBJECT));reobject.cbStruct = sizeof(REOBJECT);CLSID clsid;sc = pOleObject->GetUserClassID(&clsid);if (sc != S_OK)AfxThrowOleException(sc);reobject.clsid = clsid;reobject.cp = REO_CP_SELECTION;reobject.dvaspect = DVASPECT_CONTENT;reobject.poleobj = pOleObject;reobject.polesite = lpClientSite;reobject.pstg = pStorage;HRESULT hr = this->GetIRichEditOle()->InsertObject( &reobject );delete pDataSource;}//載入gif、bmp等圖片void COleRichEditCtrl::insertGif(CString strFilePath)  //strFilePath   gif檔案路徑{LPLOCKBYTES  lpLockBytes  =  NULL;  SCODE  sc;  HRESULT  hr;                      //print  to  RichEdit'  s  IClientSite  LPOLECLIENTSITE  m_lpClientSite;  //A  smart  point  to  IAnimator  ImageOleLib::IGifAnimatorPtr  m_lpAnimator;  //ptr  2  storage                      LPSTORAGE  m_lpStorage;  //the  object  2  b  insert  2  LPOLEOBJECT            m_lpObject;  //Create  lockbytes  sc  =  ::CreateILockBytesOnHGlobal(NULL,  TRUE,  &lpLockBytes);  if  (sc  !=  S_OK)  AfxThrowOleException(sc);  ASSERT(lpLockBytes  !=  NULL);  //use  lockbytes  to  create  storage  sc  =  ::StgCreateDocfileOnILockBytes(lpLockBytes,  STGM_SHARE_EXCLUSIVE  |STGM_CREATE  |STGM_READWRITE,  0,  &m_lpStorage);  if  (sc  !=  S_OK)  {  VERIFY(lpLockBytes->Release()  ==  0);  lpLockBytes  =  NULL;  AfxThrowOleException(sc);  }  ASSERT(m_lpStorage  !=  NULL);  //get  the  ClientSite  of  the  very  RichEditCtrl  GetIRichEditOle()->GetClientSite(&m_lpClientSite);  ASSERT(m_lpClientSite  !=  NULL);  try  {  //Initlize  COM  interface  hr  =  ::CoInitialize(NULL)  ;//(  NULL,  COINIT_APARTMENTTHREADED  );  if(  FAILED(hr)  )  _com_issue_error(hr);  //Get  GifAnimator  object  //here,  I  used  a  smart  point,  so  I  do  not  need  to  free  it  hr  =  m_lpAnimator.CreateInstance(ImageOleLib::CLSID_GifAnimator);              if(  FAILED(hr)  )  _com_issue_error(hr);  //COM  operation  need  BSTR,  so  get  a  BSTR  BSTR  path  =  strFilePath.AllocSysString();  //Load  the  gif  hr  =  m_lpAnimator->LoadFromFile(path);if(  FAILED(hr)  )  _com_issue_error(hr);  //TRACE0(  m_lpAnimator->GetFilePath()  );  //get  the  IOleObject  hr  =  m_lpAnimator.QueryInterface(IID_IOleObject,  (void**)&m_lpObject);  if(  FAILED(hr)  )  _com_issue_error(hr);  //Set  it  2  b  inserted  OleSetContainedObject(m_lpObject,  TRUE);  //2  insert  in  2  richedit,  you  need  a  struct  of  REOBJECT  REOBJECT  reobject;  ZeroMemory(&reobject,  sizeof(REOBJECT));  reobject.cbStruct  =  sizeof(REOBJECT);              CLSID  clsid;  sc  =  m_lpObject->GetUserClassID(&clsid);  if  (sc  !=  S_OK)  AfxThrowOleException(sc);  //set  clsid  reobject.clsid  =  clsid;  //can  be  selected  reobject.cp  =  REO_CP_SELECTION;  //content,  but  not  static  reobject.dvaspect  =  DVASPECT_CONTENT;  //goes  in  the  same  line  of  text  line  reobject.dwFlags  =  REO_BELOWBASELINE;  //REO_RESIZABLE    |  reobject.dwUser  =  0;  //the  very  object  reobject.poleobj  =  m_lpObject;  //client  site  contain  the  object  reobject.polesite  =  m_lpClientSite;  //the  storage    reobject.pstg  =  m_lpStorage;  SIZEL  sizel;  sizel.cx  =  sizel.cy  =  0;  reobject.sizel  =  sizel;  HWND  hWndRT  =  this->m_hWnd;  //Sel  all  text  //                        ::SendMessage(hWndRT,  EM_SETSEL,  0,  -1);  //                        DWORD  dwStart,  dwEnd;  //                        ::SendMessage(hWndRT,  EM_GETSEL,  (WPARAM)&dwStart,  (LPARAM)&dwEnd);  //                        ::SendMessage(hWndRT,  EM_SETSEL,  dwEnd+1,  dwEnd+1);  //Insert  after  the  line  of  text  GetIRichEditOle()->InsertObject(&reobject);  ::SendMessage(hWndRT,  EM_SCROLLCARET,  (WPARAM)0,  (LPARAM)0);  VARIANT_BOOL  ret;  //do  frame  changing  ret  =  m_lpAnimator->TriggerFrameChange();  //show  it  m_lpObject->DoVerb(OLEIVERB_UIACTIVATE,  NULL,  m_lpClientSite,  0,  m_hWnd,  NULL);  m_lpObject->DoVerb(OLEIVERB_SHOW,  NULL,  m_lpClientSite,  0,  m_hWnd,  NULL);  //redraw  the  window  to  show  animation  RedrawWindow();  if  (m_lpClientSite)  {  m_lpClientSite->Release();  m_lpClientSite  =  NULL;  }  if  (m_lpObject)  {  m_lpObject->Release();  m_lpObject  =  NULL;  }  if  (m_lpStorage)  {  m_lpStorage->Release();  m_lpStorage  =  NULL;  }  SysFreeString(path);  }  catch(  _com_error  e  )  {  AfxMessageBox(e.ErrorMessage());  ::CoUninitialize();              } }

 

d.IRichEditOleCallback的使用
http://61.186.252.131/Expert/topic/905/905844.xml?temp=.8379022

類似 MSN 資訊發送框的製作(上)
http://www.vckbase.com/document/viewdoc/?id=1087
內容包含:實現右鍵菜單,圖片插入,讀取/寫入RTF格式字串

自訂 CRichEditCtrl 控制項
http://www.vckbase.com/document/viewdoc/?id=328
內容包含:滑鼠右鍵訊息,訊息映射,字型變換

PS.richedit控制項升級到2.0後,先把字型設為楷體,輸入漢字沒有問題,但輸入字母時,字母自動跳轉為Arial字型,而1.0卻沒有這個文題,仍然是用楷體顯示字母
是一個專門的設計 Dual-font, Smart font apply, 參見
http://61.186.252.131/Expert/topic/913/913807.xml?temp=.3753778

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.