找回密码
 注册
查看: 7367|回复: 0

CRichEditCtrl 超文本编辑(MSN/QQ常用控件)

[复制链接]
发表于 2006-12-11 14:36:01 | 显示全部楼层 |阅读模式
一.常见问题
; l5 }7 T% `; i! w. l7 h+ }. ba.可以编译,不能执行的
) h* X. i  W9 ~4 I9 s7 oAfxInitRichEdit();2 c% S1 I' S3 h& w1 W7 q7 [. D* G4 \

& Z+ |, ?; S* O5 ]0 tb.升级默认的Riched版本(默认的有一些bug),如9 t' T+ N, ?' w
可在InitInstance中添加) L" f) U/ P, R3 S* L! R  J
LoadLibrary("RICHED20.DLL")
" D3 I: \6 e& N( t最后注意 FreeLibrary
. Z2 p# m9 E; G- s! c& O1 ^0 b# j/ _; |; s; l
如果是CRichEditView基类的可用
9 t, K* e+ y+ E, w6 R6 k% @0 yBOOL CXXXXXXView::PreCreateWindow(CREATESTRUCT& cs)  A- j0 q  o, v( W6 c
{
; I9 b. P/ l$ I' i0 b+ u- X//装入rich edit version 2.0% b# ~! P2 `* F& i. B' H0 @
if (LoadLibraryA("RICHED20.DLL") == NULL)! L; \# O& h( k$ Z# c
{. F  a4 O: G( h5 G& C. b
AfxMessageBox(_T("Fail to load \"riched20.dll\"."),MB_OK | MB_ICONERROR);
7 A/ a; @; B& P( NPostMessage(WM_QUIT,0,0);2 D0 K" a8 _+ v* A
return FALSE;( D0 M- ^6 ~) r: C& [2 w  R" N  }
}
. a# S# x" u9 B% H1 b# t. u4 f3 e0 O% r* K: F2 L. Z, v
m_strClass = RICHEDIT_CLASSA;//for 2.0 class9 v, L3 }! Z( p/ e1 F
; K; F1 Q2 d1 }& |3 x
return CRichEditView::PreCreateWindow(cs);) s* p) z9 K5 m* b
}
/ X% Z2 ?0 a" g. t: c% A7 G) X9 l
c.最后追加行* |6 ]0 i; H5 v" D$ O* P% x
richeditctrl.SetSel(-1, -1);) c% b* y6 u7 A8 ]6 n8 P; t: e
richeditctrl.ReplaceSel( (LPCTSTR)str );
: n* T3 x& Z/ Z
" o$ P1 [  [( |8 g! R+ qd.字数限制
  a% b0 B: o6 N2 z2 ]5 iCRichEditCtrl::LimitText(long nChars)
4 w1 O" ]! ^3 g# _
  a+ F8 a' v& T# _1 ke.换行切换& ?, {/ V. M- R) S: f
CRichEditView的OnInitialUpdate()函数中加入下面两句:
% P; q* ~+ l9 N  {( l) am_nWordWrap = WrapNone;$ Y8 _0 {' r1 |, _% w' M
WrapChanged();
" h' v% d' I. k  s: N1 _WrapChanged实际上也是调用/ X3 j- t( s4 i2 y" q! x
ctrl.SetTargetDevice(NULL, 1); //m_nWordWrap == WrapNone
( J7 X$ y8 n1 R& n7 cctrl.SetTargetDevice(NULL, 0); //m_nWordWrap == WrapToWindow2 X: r" m1 [4 Z3 X2 j5 t
还有不常用的 m_nWordWrap == WrapToTargetDevice
! R& Q3 u2 ]) J9 d3 e- q' e4 ]2 cctrl.SetTargetDevice(m_dcTarget, GetPrintWidth());3 N* |/ V3 R5 `: Q
如果是在Dialog中,可使用SetTargetDevice,注意在属性里面加上want return
2 V, a4 _$ B1 Z9 P- K9 ^' s2 {9 n/ d/ e; @8 h
f.有时候不希望带格式的数据粘贴,可通过PasteSpecial选择性粘贴
8 |8 h3 r; A$ N0 dpmyRichEditCtrl->PasteSpecial(CF_TEXT);
) D  k8 I, q( P; E# x! i2 P  e1 g! _- c, \, b: H$ x9 b
g.随着输入随着自动滚动条滚动到最后一行
" Y8 [4 S6 X  l- T) f, \# dint nFirstVisible = pmyRichEditCtrl->GetFirstVisibleLine();
; M; L" v7 l8 H" Sif (nFirstVisible > 0)
% M* d- x6 C1 n1 u{& J2 b: a" [" C
   pmyRichEditCtrl->LineScroll(-nFirstVisible, 0);) j7 n5 W' J. @1 H* X: h5 S% b. A
}  `  x1 M6 F' ^
或
- R1 U% P8 |6 A- P. t" a% Tm_cRichEdit.PostMessage(WM_VSCROLL, SB_BOTTOM,0);
! U! _7 a+ A1 K: Q0 Z1 z- n- i& T9 w6 x4 h2 ~) S( g

3 A$ b1 W% }: vh.设置UNDO的次数(只能用在RICHED20以上,即默认不支持,必须升级)7 s+ r& {" v6 H5 v# i
SendMessage(EM_SETTEXTMODE,TM_MULTILEVELUNDO,0);* f* {1 N% ^" p2 c$ V
TM_MULTILEVELUNDO 支持多取消(默认值).可通过EM_SETUNDOLIMIT设置最大次数 1 c+ b6 S% o- p5 ]; r/ e
SendMessage(EM_SETUNDOLIMIT,100,0);
3 u( T. w$ F! x4 P) g7 h# f& a2 _9 @: t9 o# M( Q+ k; b
i.响应OnChange
5 x5 s+ r# M; `8 d( i. JEM_SETEVENTMASK 设置 ENM_CHANGE
9 w" W1 {4 `3 y; k! Q; E+ ilong lMask = GetEventMask();
% r6 C1 a0 J. L$ F, r8 }2 clMask |= ENM_CHANGE;+ N; I, X# ]" E/ z: U4 Q* O9 C$ _2 \6 }. J
lMask &= ~ENM_PROTECTED;
+ m. @/ x- e/ v" l& X& y6 FSetEventMask(lMask);
6 R9 b0 S8 u9 v1 A2 j
, t' N/ c0 k( Ij.设置只读
5 j, E" Y- l* N+ \CRichEditCtrl::SetReadOnly( BOOL bReadOnly = TRUE );$ e! W& M8 L& G0 s* e& l0 ]2 J
通过设置PROTECTED实现选中的文本只读,参见. S& u# v: u' d7 K/ ^
http://www.codeguru.com/Cpp/controls/richedit/article.php/c2401/1 m1 ^: `6 D9 |& W" a7 O
0 p. s1 Y& ~# k
二.函数应用
, b: l8 ?$ Z9 z* ba.设置字体(主要是通过SetSelectionCharFormat)! c: s; U( `2 `0 w/ P$ I4 Q, b
CHARFORMAT cf;
8 E( A9 Q( H# K3 W( Z8 n0 Q/ Vrich.GetSelectionCharFormat(cf);
) T7 S9 ?6 M: p; N5 ?cf.dwMask|=CFM_BOLD;
& C" |! X; ]/ e9 r& {+ D% Ycf.dwEffects|=CFE_BOLD;//设置粗体,取消用cf.dwEffects&=~CFE_BOLD;* g& B7 d( z1 h2 }/ ~7 \
cf.dwMask|=CFM_ITALIC;( p) C  j( z( l
cf.dwEffects|=CFE_ITALIC;//设置斜体,取消用cf.dwEffects&=~CFE_ITALIC;% }1 x9 c+ q) B8 K& @/ ^/ c" h
cf.dwMask|=CFM_UNDERLINE;9 s( t, D: p; A( }+ R$ ?3 T
cf.dwEffects|=CFE_UNDERLINE;//设置斜体,取消用cf.dwEffects&=~CFE_UNDERLINE;
# e1 ]. ]1 C3 s2 ]- }cf.dwMask|=CFM_COLOR;) _! Q) N" y1 n: p; y: Q3 V
cf.crTextColor = RGB(255,0,0);//设置颜色
( z: u: q4 C# I/ D! z8 jcf.dwMask|=CFM_SIZE;
9 x. E# i3 j1 j- Qcf.yHeight =200;//设置高度
# v% d; S0 t' R$ n; Y  i  Xcf.dwMask|=CFM_FACE;. ^8 a: o$ J6 H9 {7 i
strcpy(cf.szFaceName ,_T("隶书"));//设置字体/ }8 S( l- R! B; L2 R- Y! _
rich.SetSelectionCharFormat(cf);
2 j% w* ^3 Y2 s9 o- l; |7 r5 L" `6 x/ [. V
b.设置字体的行间距' z1 o. {8 P4 D, D
要用richedit2.0以上# {- u, L; X, h6 h8 U
试试
$ o3 r; D$ L( X5 ^3 q  mPARAFORMAT2 pf;' x# r, w  P$ e2 z
pf.cbSize = sizeof(PARAFORMAT2);
' i" g# m5 R3 ^: o7 f$ o5 ipf.dwMask = PFM_NUMBERING | PFM_OFFSET;. y; z) C1 t* Z& N; q' P
pf.wNumbering = PFN_BULLET;//注意PFM_NUMBERING
9 G) c  C' q$ V; Lpf.dxOffset = 10;5 g, \- ^9 l& i0 M
VERIFY(SetParaFormat(pf)); / ~6 a/ ^: u+ v: w! P6 V+ ]: [
常用的dwMask有
8 d9 ]# T6 k( f( U: o4 UPFM_NUMBERING 成员 wNumbering 才起作用,项目符号,默认用PFN_BULLET
. ^; |9 ?/ F8 N( `" ?2 使用阿拉伯数字 (1, 2, 3, ...).  0 d6 \( W/ o" s7 e6 J4 R
3 使用小写字母 (a, b, c, ...).  9 U3 |8 ~! `- M+ i
4 使用大写字母 (A, B, C, ...).  
  c  i3 I: ~" h, P- R+ y- Q5 使用小写罗马数字 (i, ii, iii, ...).  
$ f3 c+ f$ \" a4 R- K$ u. O! ~6 使用大写罗马数字 (I, II, III, ...).  
5 s! D' J! ]8 J* h' x! y7 自定义,字符见成员 wNumberingStart.  5 k  o8 h. V" o$ o5 C# n+ o
PFM_OFFSET 成员 dxOffset 才起作用,缩进,单位twips
1 [5 |8 b3 D' b* KPFM_STARTINDENT 成员 dxStartIndent 才起作用,首行缩进
3 c/ I, ]' b7 k% n! nPFM_SPACEAFTER 成员 dySpaceAfter 才起作用,段间距
. l( ^( J; B: k# [/ ]) D/ n' MPFM_LINESPACING 成员 dyLineSpacing 才起作用,行间距
* P1 {. R% g9 |! T( `1 v/ s) G/ z7 S7 M0 A  D
c.设置CRichEditCtrl(2.0)背景透明
4 \0 \9 k* e- }" O+ J2 ulong style = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
" N( R& }3 v2 h- K2 d* Q) R& Q0 @style &= WS_EX_TRANSPARENT;
: U0 G8 g: t5 H::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, style);
+ w, B" N4 ?0 I9 t& W" l" y或 CreateEx,然后把WS_EX_TRANSPARENT样式加上
9 j2 J8 `& H1 W) Y, t$ x
: N- z) P/ K8 s8 W3 Me.得到内容有三种& J# |% ~9 I+ H
1)GetWindowText, E* H3 `; k6 \( \
2)使用EM_GETTEXTEX6 o! Y( [5 @) s6 n4 L
GETTEXTEX gt;7 f7 j3 U4 s6 T2 ~& M1 \
gt.cb = 200;
& ^9 f! o, z- W- y! ogt.flags = GT_DEFAULT;
6 v& r8 Y8 C  Qgt.codepage = CP_ACP ;& R0 Z2 B6 e/ ?1 @$ m  N
gt.lpDefaultChar = NULL; ; O2 R0 e! p4 p' e; K
gt.lpUsedDefChar = NULL;
& L* V( M( j; ^/ t# j# ]! ySendMessage(EM_GETTEXTEX,(WPARAM)&gt,(LPARAM)text);
% L" S: y# }. r% x3)StreamOut(主要用于RTF等格式输出)
) C; L5 J1 L6 e: wstatic DWORD CALLBACK
; D9 i9 z- F4 r$ R( J! k5 R; k: EMyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
% @6 w, }% {- P& @0 y{
) b9 `# M- B! B   CFile* pFile = (CFile*) dwCookie;' e) U5 F6 ~9 z4 [2 s& S

: Q0 D7 v( w1 X4 N3 g   pFile->Write(pbBuff, cb);+ O- P6 }' q( K# b# m4 U
   *pcb = cb;! k2 x  B8 z  C) U6 c+ A: }! H" T

& s/ N9 Q0 i  m. e+ A2 {* ^) `) d   return 0;' c0 R8 @+ C$ l2 b5 J
}
" {: w2 O& L' p$ o' n. w/ @3 `  W- Z" Z& n' H0 j
) Q4 Z4 z/ B; {# ?2 p7 v- z
   CFile cFile(TEXT("myfile.rtf"), CFile::modeCreate|CFile::modeWrite);" o: i$ n5 R  Q5 p) T
   EDITSTREAM es;
# P! y* Q' G* Y% y$ a9 X   es.dwCookie = (DWORD) &cFile;//设置用例参数,以便回调函数调用
+ F+ S  r9 }( J# v; g% @4 w& X) G   es.pfnCallback = MyStreamOutCallback; - |1 A, \9 u+ U# Z
   pmyRichEditCtrl->StreamOut(SF_RTF, es);
4 e) A& H. Z1 }; g! t7 {: Q读入可以此类推,SetWindowText,EM_SETTEXTEX,StreamIn" d8 ~; G5 b9 j: r3 ]+ x
4 O0 n0 P  B/ n+ N1 ]# [
f.查找字符串2 c. o" ^/ C! b0 o
FINDTEXTEX ft;  ?2 j7 s! t- W/ @
ft.chrg.cpMin = 0;( q* T; W2 W. U6 [- t( c2 s% E
ft.chrg.cpMax = -1;$ a0 U' h( Q6 Q6 ]. h
ft.lpstrText = "|";' s$ p. n9 Y) k0 N6 Y6 ~' m- P6 J7 s
long lPos = FindText(0, &ft);1 G& M: c, c* i) f3 n; i, y2 F

' g* F3 m4 C( Y4 E- `$ e, P, u如果要继续查找,修改cpMin,如
6 o: B- H3 S! z# n* n0 J; Iint nCount = 0;( C, z8 [! q7 z" ]! Y
do
. Q$ I% |- q# k{
8 [  C* |/ x# ~. w long lPos = GetRichEditCtrl().FindText(0, &ft);8 d" I  w. l7 a# f/ {* E
if( -1 == lPos) break;. [! f9 |8 U0 Y0 w/ U. H2 k# o
ft.chrg.cpMin = lPos + strlen(ft.lpstrText);* S0 j- X( Y' p( z& [
++nCount;
+ L; I* d; `+ @. N* L- r0 q7 l}while(TRUE);+ @- f7 u5 }! t- R- W3 L

1 ~4 y  r$ |: b/ L) W8 tg.以Html格式保存8 ?" ?+ }( x# |( \- a
目前做法可先转为RTF格式,再通过RTF-to-HTML Converter8 s! f; K+ \( e8 G; z
http://www.codeguru.com/Cpp/controls/richedit/conversions/article.php/c5377/9 Q8 j- u: ~1 c
' p6 P1 b' Z% w0 W  y3 F
h.重载OnProtected函数得到对应的消息,如粘贴等) G6 B( ]5 L+ |) c& C/ D0 i% j- y
void CMYichEditorView::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)
% W4 U' Q9 h: v" o( d* p6 }{
: |, a+ {1 o& f ENPROTECTED* pEP = (ENPROTECTED*)pNMHDR;5 R: c1 k5 P, T! Z

: w% t# j2 j; }8 B2 a8 q4 d7 P switch (pEP->msg) {
3 W0 d3 ^8 ~) i- x& N case WM_KEYDOWN://按键,判断pEP->wParam
. M2 [2 D5 m9 i9 @* a0 G case WM_PASTE://粘贴' `9 j; @7 i! n) h
case WM_CUT://剪切# s3 l* c5 a) w7 s9 R* |
case EM_SETCHARFORMAT:
0 {/ J% k' R1 i/ Q' g default:
. m1 S6 l; y) b& M0 B; R! T0 m; X' |  break;$ }' g# r6 B& U* G' ~3 u( {
};
: }. e& y, U# }
, X  p* y# E! a1 l. P* M *pResult = FALSE;( B0 I$ z2 G7 a8 F! u$ X* w
}, f: J5 {7 I; c7 o: m/ e: \
+ B0 T1 V$ Q0 l
三.聊天常用  
3 e% s; b) [6 o* _' C) [# ~a.LINK 链接功能
1 V' b" k3 |+ |1.  LoadLibrary(_T("Riched20.dll"));
8 }+ L) k; D( R* L4 b* e$ N& I3 K. d2. 创建RichEdit2.0控件
  c4 P1 N$ M' M: J$ A& q CreateEx(0, _T("RichEdit20A"), NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP& o! h; O' Q/ X# y! m$ t4 q
|ES_READONLY|ES_WANTRETURN|ES_MULTILINE,
. h; z$ e. j( ?          rect.left, rect.top, cx, cy,: Z! _2 O) T8 s" Z( a2 o' l% m; l0 B+ q
  pParentWnd->m_hWnd, (HMENU)nID, NULL);
3 d3 e2 C$ a( P( H3. 设定选中的文字为链接显示( ~/ e  m  r: k/ \/ Q
CHARFORMAT2 cf2;
% Q8 h- k0 r* m" P: tZeroMemory(&cf2, sizeof(CHARFORMAT2));//3 C$ y" z3 M8 A
cf2.cbSize = sizeof(CHARFORMAT2);/ Y( O! t8 ^5 g8 z3 B1 o0 @
cf2.dwMask = CFM_LINK;. B8 N& K, p' ?. O- b
cf2.dwEffects |= CFE_LINK;/ x; U, B" P& a  B
m_cRichEdit.SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
: Q/ V2 i/ x, ?  x, O4.支持链接的点击响应$ O3 x' c- b9 }  a9 k  t8 B( F
m_cRichEdit.SetEventMask(ENM_LINK);5 c! M9 z3 U" \- T- U( @
5.响应链接的点击EN_LINK3 D+ u" R( B* X

, n4 T9 l  c6 @: }( @8 HBEGIN_MESSAGE_MAP(CMyRichEdit, CRichEditCtrl)# d- u5 t2 F$ Q/ _
ON_NOTIFY_REFLECT(EN_LINK,OnURL)6 I7 g/ x5 D0 w, D5 G% ]! w
END_MESSAGE_MAP()
0 n7 K1 _. \& ?: W; i) n......
2 n' A! ^: E, [- C
1 ?# R: h+ l: L5 Z; C, n. zvoid CMyRichEdit::OnURLClick(NMHDR *pNmhdr, LRESULT *pResult)
4 t& J) w& Q; [% i{
8 V% I6 G# \8 o1 |TCHAR LinkChar[512];
) g' `5 w5 `5 ^9 d  HENLINK *pLink = (ENLINK *)pNmhdr;
: T; D+ I  p: m, Rif (pLink->msg == WM_LBUTTONUP)
3 |0 T2 i3 c. O4 Q: y; A( K{
! c4 {! \3 \- G* `* I# lSetSel(penLink->chrg);//这是链接的文字范围6 Q# ]/ I5 N0 i% A* H
long Res = GetSelText((char *)LinkChar);//这是链接文字
; Q' q6 [3 F1 ^, r- O1 h; V6 o                  //后面是你的处理过程9 D6 e2 R6 s: L7 Z  g
                  ......
  j* D/ ^' C" }6 M         }
+ ?6 Y# L: U% _) h4 Q}
' @% G5 |4 L6 b! [. A/ I0 }
6 l4 e( C& o8 ^2 X7 Wb.插入位图
; U: F& ]/ b  u& ^, }http://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/
! }2 k0 H. e" P$ W  Phttp://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/
, t  Q6 D# @, L6 D1 N- ?6 h+ T4 }! e  h4 |$ C
自定义在RichEdit中插入对象的图标2 X4 S2 z. `9 Z) ^; p2 V1 t( u
http://www.blogcn.com/user3/jiangsheng/blog/1319738.html
' q) l! H- I& h& u方法基本同Knowledge Base文章Q220844 HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control" W4 a9 [6 T) V  {7 f
只是在最后插入之前调用一下IOleCache::SetData,用一个HGLOBAL作为参数,HGLOBAL里面的数据是一个METAFILEPICT结构,包含自己提供的图片& U3 A& x1 }0 _4 C2 B8 y; n

1 p, ^+ |9 R$ ]0 ]" v使用CRichEditView::InsertFileAsObject就可以插入图像。VC++带有一个例子WordPad。
7 A! W# ~* d. L; a' L; R4 p. u另外可以参考“Insert any HBITMAP (Bitmap) in your RichEdit Control”(http://www.codeguru.com/richedit/richeditrc.html)。 * f9 p# F4 a% G; I

, }; q) w' D( kc.显示GIF动画# V2 L* r( e* a1 d# l1 ^2 r. a; G
常用的是通过qq的imageole.dll(也有用Gif89.dll的)
# R, @& N  j! I2 Jhttp://www.xiaozhou.net/cooldog/blogview.asp?logID=82
' ^, U( G+ K5 Hhttp://www.codeproject.com/richedit/AnimatedEmoticon.asp$ A' F9 E; a" y; E% w) i
( }& j; S4 F: I0 ~/ X
在richedit控件中插入动态GIF (Native C++版)
& N& _! L& K  ~1 }7 ^http://blog.joycode.com/jiangsheng/archive/2004/12/15/41209.aspx' @/ `; p6 J% d0 F) a1 p

: o3 H7 M" I; zd.IRichEditOleCallback的使用7 T( ~9 g6 @) m& K( G; b4 v  o
http://61.186.252.131/Expert/topic/905/905844.xml?temp=.8379022
! ]+ R# E9 x* O$ ?" ^+ b# i8 P. ?, ^7 @8 M4 C6 o
类似 MSN 信息发送框的制作(上)
  R( y+ K; ]4 ]8 O7 Dhttp://www.vckbase.com/document/viewdoc/?id=1087
7 \/ x+ Y; w  _1 n  s2 @- }$ i内容包含:实现右键菜单,图片插入,读取/写入RTF格式字符串
9 e, p' J9 R# V- D+ g' m* G$ k3 r
自定义 CRichEditCtrl 控件+ A/ g; v; H, g
http://www.vckbase.com/document/viewdoc/?id=3285 d5 Z' H0 b0 x2 Q8 O( R
内容包含:鼠标右键消息,消息映射,字体变换! L5 j/ e8 H% z7 a
. R# E# Z) V' d% p
PS.richedit控件升级到2.0后,先把字体设为楷体,输入汉字没有问题,但输入字母时,字母自动跳转为Arial字体,而1.0却没有这个文题,仍然是用楷体显示字母
8 m0 w/ D5 A. e2 I是一个专门的设计 Dual-font, Smart font apply, 参见 http://61.186.252.131/Expert/topic/913/913807.xml?temp=.3753778
3 b; ?% H# d: n0 c+ r  \----------------------
  Y; n4 x% m6 |0 F- q8 u# C比我想象中还要花时间,所以最后潦草了点,见谅
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|宁德市腾云网络科技有限公司 ( 闽ICP备2022007940号-5|闽公网安备 35092202000206号 )

GMT+8, 2026-10-1 20:49 , Processed in 0.019820 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表