找回密码
 注册
搜索
查看: 7188|回复: 0

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

[复制链接]
发表于 2006-12-11 14:36:01 | 显示全部楼层 |阅读模式
一.常见问题1 [! Y! D3 W  O1 E
a.可以编译,不能执行的
7 C# o' ~: _! i! ?* iAfxInitRichEdit();
. Y  v0 Z, h  U) Z% @
) c( U' E, {! `b.升级默认的Riched版本(默认的有一些bug),如
; X& \* p9 {; H' u" J& c可在InitInstance中添加
+ ~/ ?& y& C8 X0 X' N7 C: s) ALoadLibrary("RICHED20.DLL")   B1 b8 C8 W( j: P
最后注意 FreeLibrary
4 A2 p3 q9 J) T
$ v  i! E6 s$ S如果是CRichEditView基类的可用& ^( _2 {# H$ S8 `
BOOL CXXXXXXView::PreCreateWindow(CREATESTRUCT& cs)
7 T& \( v3 s% X9 w( ~{
( l' @+ V) V4 r$ {0 n//装入rich edit version 2.0
; h0 e9 g- U5 y$ Yif (LoadLibraryA("RICHED20.DLL") == NULL)$ D3 ~+ s6 N) C2 o% u
{
# Q. z/ u' f3 `" a# _, }9 GAfxMessageBox(_T("Fail to load \"riched20.dll\"."),MB_OK | MB_ICONERROR);
0 T9 g- |& ?3 dPostMessage(WM_QUIT,0,0);
& F" p# ]" `- Q( Z9 c& yreturn FALSE;
5 B9 X9 ~( Q6 T+ W! _3 Q8 U}2 H& s1 f4 G! X  E/ V0 j3 r; d

/ y5 Y6 L6 T% E1 E1 e# Bm_strClass = RICHEDIT_CLASSA;//for 2.0 class
1 a+ n8 u& I2 |* \6 N' N5 I5 ~: c6 x3 Y) k. g
return CRichEditView::PreCreateWindow(cs);
* r0 `3 |. j3 u0 I8 m}6 N9 N, r8 c5 ]* d
, v4 D8 g: {$ ~; f3 W
c.最后追加行
- D3 M  w7 v4 L5 ericheditctrl.SetSel(-1, -1);4 B, J2 C) c! D- t/ B; W. K5 k
richeditctrl.ReplaceSel( (LPCTSTR)str );
1 x5 D4 I3 e# K5 \  }5 H" F3 |. q& I/ J' {
d.字数限制
, i" Y% ?( g1 U! w' w& c6 nCRichEditCtrl::LimitText(long nChars)
9 g% a! `1 F7 ^, |  w8 m' n1 }- P2 G. ?6 J
: [; {# k4 _3 he.换行切换7 E, ]: j$ p" p5 x; Y
CRichEditView的OnInitialUpdate()函数中加入下面两句:
. t* S* w, e1 E8 o& c8 E5 fm_nWordWrap = WrapNone;5 o- [; G. s  P. w7 O0 U. Q! |+ d) }  i
WrapChanged();
* c/ d! H2 {: s5 k7 k9 iWrapChanged实际上也是调用4 ^. ]( ^( j: L0 ]% y  k/ X+ k' n
ctrl.SetTargetDevice(NULL, 1); //m_nWordWrap == WrapNone
" g* n( c) E; A; H/ _* z' E0 lctrl.SetTargetDevice(NULL, 0); //m_nWordWrap == WrapToWindow; I  J! X; ^6 k! `' D3 R! l
还有不常用的 m_nWordWrap == WrapToTargetDevice
8 T- q' M* d  k: G3 mctrl.SetTargetDevice(m_dcTarget, GetPrintWidth());. J' Y5 ]4 d- J& _2 D" }! D
如果是在Dialog中,可使用SetTargetDevice,注意在属性里面加上want return
9 @' O% a8 u- ]- g) T
6 D& p/ I$ w$ if.有时候不希望带格式的数据粘贴,可通过PasteSpecial选择性粘贴
7 h0 n8 p- i+ _: H& v$ d" T5 {pmyRichEditCtrl->PasteSpecial(CF_TEXT);: R& x# Y! U! p# d
5 i( W$ y8 b" u* e3 r
g.随着输入随着自动滚动条滚动到最后一行! P7 u) o" x" [" e1 b( ?, o! v
int nFirstVisible = pmyRichEditCtrl->GetFirstVisibleLine();
1 {: P4 c. W7 p& a. e$ Gif (nFirstVisible > 0)
7 `7 y/ O  v7 P8 H1 {, T& ]1 N. S{
, F. K+ ?, X. f# Z9 Y8 q. v   pmyRichEditCtrl->LineScroll(-nFirstVisible, 0);
; @4 ]$ l& {" E: w}) [) t& [- a' E+ C" n  d$ G

) P6 _% X" }# Q; K- fm_cRichEdit.PostMessage(WM_VSCROLL, SB_BOTTOM,0);7 K8 x7 _5 \7 J* X4 Z/ {" V

" }. k* m# v, @1 M3 I: K8 b
- c/ `& p/ j) n0 _8 z6 ~h.设置UNDO的次数(只能用在RICHED20以上,即默认不支持,必须升级)
  B9 w7 |9 W4 x2 s$ x3 ^! l' VSendMessage(EM_SETTEXTMODE,TM_MULTILEVELUNDO,0);/ c/ H1 P. j; J
TM_MULTILEVELUNDO 支持多取消(默认值).可通过EM_SETUNDOLIMIT设置最大次数
# }# J; E% h. l0 `7 FSendMessage(EM_SETUNDOLIMIT,100,0);
8 m  ]/ [/ i9 D, x! U) e4 P$ N% ]7 [
i.响应OnChange8 u; i' w' D5 k5 T6 X" w
EM_SETEVENTMASK 设置 ENM_CHANGE
! H$ _0 x- n# s3 }+ B8 l* Xlong lMask = GetEventMask();: i/ n* C# }: b+ c+ E" @, t
lMask |= ENM_CHANGE;/ K8 u; t2 f3 z0 q' |1 z
lMask &= ~ENM_PROTECTED;
6 }; ]& [. C7 i& z7 S5 kSetEventMask(lMask);
  I* U3 k, s/ \7 _; P. P3 W5 K. W8 Z9 ]
j.设置只读
% j! T# ?( z# }& D+ u2 S+ k: b* YCRichEditCtrl::SetReadOnly( BOOL bReadOnly = TRUE );$ J( E( B; m/ S3 b
通过设置PROTECTED实现选中的文本只读,参见. e. |% h% A( H$ {2 O& _
http://www.codeguru.com/Cpp/controls/richedit/article.php/c2401/
# f( V7 m) H* n
" B1 {5 ~# m2 _) X( W6 P1 V二.函数应用5 k1 i1 z! q/ M+ r4 k2 A% R
a.设置字体(主要是通过SetSelectionCharFormat)
9 f8 i* I1 v+ J" y% V/ g& N+ A4 ]9 BCHARFORMAT cf;2 n3 v: A4 y7 m& y1 }) M2 {
rich.GetSelectionCharFormat(cf);
& u9 \7 j0 K5 o# x5 z& ]+ Y; Xcf.dwMask|=CFM_BOLD;
, Z2 ?4 v. z$ T" ucf.dwEffects|=CFE_BOLD;//设置粗体,取消用cf.dwEffects&=~CFE_BOLD;
$ H7 C4 L: {" U7 Acf.dwMask|=CFM_ITALIC;, U6 t* _6 K# X+ [; f* G
cf.dwEffects|=CFE_ITALIC;//设置斜体,取消用cf.dwEffects&=~CFE_ITALIC;
; f! V- F- K) n/ S& |% Jcf.dwMask|=CFM_UNDERLINE;; c7 r0 o/ z. ?- I" `( _. s
cf.dwEffects|=CFE_UNDERLINE;//设置斜体,取消用cf.dwEffects&=~CFE_UNDERLINE;  c. h8 ~. x& t. n( r, F
cf.dwMask|=CFM_COLOR;  g# |* F5 ]& t& I: Z& v2 n
cf.crTextColor = RGB(255,0,0);//设置颜色" g6 ^6 @: F, P; E# j0 N% {
cf.dwMask|=CFM_SIZE;3 O- Q/ }* ~/ Q- j5 [' g; a* Q
cf.yHeight =200;//设置高度
3 N- @7 B5 D. O# c. @1 V7 Z# [: Q: H  Ucf.dwMask|=CFM_FACE;
  y8 [5 O$ f" X8 V5 ^* ostrcpy(cf.szFaceName ,_T("隶书"));//设置字体* v7 v9 ^6 m" b3 |3 [
rich.SetSelectionCharFormat(cf);
( c9 y+ ^: {' F; G: c+ _) ?
/ _0 A% ?0 ]; ?5 r+ E& l8 }% Ob.设置字体的行间距
9 N& C- G$ |2 {4 D) x' u) \要用richedit2.0以上9 l3 h# c: ^; Y) _8 g
试试$ v1 {/ I$ R. O* H
PARAFORMAT2 pf;4 u9 a  w& I' X
pf.cbSize = sizeof(PARAFORMAT2);& ^3 T+ k; n+ w* M
pf.dwMask = PFM_NUMBERING | PFM_OFFSET;
2 }3 t2 }, H# D0 `  r1 b8 j# Jpf.wNumbering = PFN_BULLET;//注意PFM_NUMBERING
  L0 n8 q0 w  n- W+ Q, Apf.dxOffset = 10;
; @! z7 }& u2 U$ A# WVERIFY(SetParaFormat(pf)); : w! G" y( h* {( Q
常用的dwMask有
; Y4 p# ]* A; n5 ^! n6 SPFM_NUMBERING 成员 wNumbering 才起作用,项目符号,默认用PFN_BULLET4 u+ k2 R4 q3 o5 J2 r1 s
2 使用阿拉伯数字 (1, 2, 3, ...).  * k! T: ~% S2 N* l( d
3 使用小写字母 (a, b, c, ...).  ' e1 c! W9 Q* u& P
4 使用大写字母 (A, B, C, ...).  . U8 l& k8 u+ [) }
5 使用小写罗马数字 (i, ii, iii, ...).  
( {# ?8 m% B, \, `: e2 e- ~$ \% v6 使用大写罗马数字 (I, II, III, ...).  ( z5 r; s% |, j  O8 P
7 自定义,字符见成员 wNumberingStart.  ( l" f; }8 h- N' d
PFM_OFFSET 成员 dxOffset 才起作用,缩进,单位twips
- D  n; g1 D. L' `) `6 A- _PFM_STARTINDENT 成员 dxStartIndent 才起作用,首行缩进
& g  R8 x& M7 f: {! l5 z: X0 P+ iPFM_SPACEAFTER 成员 dySpaceAfter 才起作用,段间距2 `/ h$ d5 n: @) H: ]
PFM_LINESPACING 成员 dyLineSpacing 才起作用,行间距
$ M7 R3 s+ {2 j
6 H% V) j! p5 v, ]c.设置CRichEditCtrl(2.0)背景透明 ) r3 A2 ~2 q: b$ s' O2 a* s* n: \
long style = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
& `' O- ~2 v& J3 U9 ^% Cstyle &= WS_EX_TRANSPARENT;/ \' q3 S/ s+ k5 ^9 ?0 S
::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, style);, f9 ?6 L* w7 I: O
或 CreateEx,然后把WS_EX_TRANSPARENT样式加上
* P8 w" l" I5 E! Y9 n8 o' B" z7 Y9 R1 f0 ?0 ?# i3 S
e.得到内容有三种4 w# Y! L" D  Z4 _4 \9 B
1)GetWindowText
# C) H$ b: I1 }, U+ K4 ^+ e/ ]/ g2)使用EM_GETTEXTEX/ ], l4 j2 w7 ~5 Q0 R
GETTEXTEX gt;
+ O. O! d  ~8 \; ?+ M3 V: G: x& U4 ^gt.cb = 200;4 W6 @( R6 Y; X  B2 @6 C- @% V; `
gt.flags = GT_DEFAULT;
8 p% \( K) U% Q. a8 W$ _gt.codepage = CP_ACP ;* ]/ J1 q" @: b. v
gt.lpDefaultChar = NULL; " k( }% Z- ]* F/ v
gt.lpUsedDefChar = NULL;
9 F5 M, T) l& [2 B2 g/ KSendMessage(EM_GETTEXTEX,(WPARAM)&gt,(LPARAM)text);
' }2 f; r- |4 X# ?  {" t3)StreamOut(主要用于RTF等格式输出)
: o: L! |8 q/ l7 {2 fstatic DWORD CALLBACK
, D! a7 ?- P6 Y- y! h; z* _. fMyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)" ]/ w: Y9 I5 H0 t2 L, T
{# _9 M9 {( c3 x! J
   CFile* pFile = (CFile*) dwCookie;9 y  z6 f0 I5 Q5 g$ _: D5 Z
' Y$ Y7 a  d' B
   pFile->Write(pbBuff, cb);
3 c+ _! X/ W. c6 [1 l5 `) f   *pcb = cb;  [/ c6 j3 X3 x; L' ?

, }, F& }+ z) z: z2 f   return 0;, t( N( a5 f$ `' p  B5 C
}' D( j2 v: }7 Y3 U  I5 e

' W  U  R. ]6 z- Q5 ]8 d- ~" C$ I& l4 T' q- ^/ h! [5 Y: b
   CFile cFile(TEXT("myfile.rtf"), CFile::modeCreate|CFile::modeWrite);
7 k, O# Y5 N) G, U  f6 w5 i   EDITSTREAM es;
6 Y) \) A8 n' e* v   es.dwCookie = (DWORD) &cFile;//设置用例参数,以便回调函数调用7 {0 Q$ ^  r2 v
   es.pfnCallback = MyStreamOutCallback; # ~' A( n9 C: V7 j* t3 ?$ @
   pmyRichEditCtrl->StreamOut(SF_RTF, es);
, ]3 W, z/ C# I5 m6 C* }, @( Q7 h读入可以此类推,SetWindowText,EM_SETTEXTEX,StreamIn% D+ d; p  M$ N4 X8 Q

: U* {$ S+ `+ If.查找字符串
- Z+ @- k# _& k: j0 b5 kFINDTEXTEX ft;0 L0 Y+ R% @: I# Y
ft.chrg.cpMin = 0;
7 j* Z4 g7 G, L7 hft.chrg.cpMax = -1;
( [* o4 w- F( n! Dft.lpstrText = "|";
1 ]! M5 `8 N) ?" K+ jlong lPos = FindText(0, &ft);
9 L* n1 w( {; g+ U
& b2 _+ s; Y- O4 W如果要继续查找,修改cpMin,如
: r2 j# Z) ]8 L/ fint nCount = 0;
4 l. K- D( Y5 ydo
/ d; c, U0 m& k% Y1 z{8 F+ V9 U9 M- R/ H4 H
long lPos = GetRichEditCtrl().FindText(0, &ft);
3 ~9 N$ m, E/ T; v! C* L if( -1 == lPos) break;
% p, ^) u! m( r% P! \. c ft.chrg.cpMin = lPos + strlen(ft.lpstrText);2 k+ V: _7 g; Q5 [& |
++nCount;
' R, b* @& q# x5 q}while(TRUE);
; f5 m/ n, }; z9 B& w
4 E8 Z1 w) e. `% b7 {g.以Html格式保存9 o( w& {* U% |
目前做法可先转为RTF格式,再通过RTF-to-HTML Converter: F& c: J5 l2 \2 N1 I4 ?
http://www.codeguru.com/Cpp/controls/richedit/conversions/article.php/c5377/, |1 j" j( `6 x! }5 g" D! D
$ g) [# p8 g; U, ~* m" \
h.重载OnProtected函数得到对应的消息,如粘贴等+ |& l# x+ d& P( Q- ]) h% p
void CMYichEditorView::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)
: Y, W( g4 g( s3 o9 N) u{
4 l8 X7 }/ q! o& k  k; K ENPROTECTED* pEP = (ENPROTECTED*)pNMHDR;
: C, q5 i9 _. _( F/ S. f' I2 g  T9 f% a
switch (pEP->msg) {; ]( [- G6 i! Y! j% Q
case WM_KEYDOWN://按键,判断pEP->wParam
7 c' @, h5 F; @  s& J+ G9 o case WM_PASTE://粘贴( a& y+ R4 n% p8 X2 |4 P6 S
case WM_CUT://剪切
) C5 P: E4 N8 l: B case EM_SETCHARFORMAT:0 q5 X7 V  s1 q: a
default:, r9 f/ T; w( X1 q
  break;  \  W2 e& P' Y. W/ v% \
};
0 }( ]* u9 C( ? ) F1 c. K& ], _. G
*pResult = FALSE;9 u8 L' r# K( [3 ^% t  ^# ]; K
}& C. j2 |9 J) ?5 A
6 Q2 A7 C7 m) o* e% |, U2 q5 o& G
三.聊天常用  
# P- K3 t. @, O8 da.LINK 链接功能
1 L9 I) L; r" i7 h1.  LoadLibrary(_T("Riched20.dll"));: R$ E; S4 M, m/ ]; P
2. 创建RichEdit2.0控件8 P2 ~# P6 b2 t8 w, x0 M' ?9 e% g1 ?4 Q
CreateEx(0, _T("RichEdit20A"), NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP
/ x6 g& K* Y! \4 V0 l+ Q|ES_READONLY|ES_WANTRETURN|ES_MULTILINE,
' w! e) u& X# `2 E* d/ [$ X          rect.left, rect.top, cx, cy,; H6 r, w) c  D. g
  pParentWnd->m_hWnd, (HMENU)nID, NULL);. Y9 C. m* P, S* c/ Y: ~
3. 设定选中的文字为链接显示
& r9 d  o/ v# a' [CHARFORMAT2 cf2;0 X# W3 o5 @3 \! M
ZeroMemory(&cf2, sizeof(CHARFORMAT2));//
! E% M/ S# F; }" Bcf2.cbSize = sizeof(CHARFORMAT2);% U. m  G. U, G
cf2.dwMask = CFM_LINK;" P2 v; e: b5 A
cf2.dwEffects |= CFE_LINK;
* N; o3 i8 I& \) K" v8 Bm_cRichEdit.SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
& R5 b7 O! L* T' Y# N; h4.支持链接的点击响应
2 t7 @5 \; {+ z/ W( wm_cRichEdit.SetEventMask(ENM_LINK);
+ u1 B& n, L- e$ v5.响应链接的点击EN_LINK
: v$ r; P1 T; }8 ?. G. {, s
$ {3 N5 u7 a; F2 n: N/ ABEGIN_MESSAGE_MAP(CMyRichEdit, CRichEditCtrl)
+ c* a6 a7 ~( i0 QON_NOTIFY_REFLECT(EN_LINK,OnURL)
) u1 c) `3 L' C: \  x' a5 {+ pEND_MESSAGE_MAP()
3 H4 L, M# f- S......
' w( K9 _" l' [. p/ y0 r0 m" f; \* @; n( m/ a: B4 ~5 j' K
void CMyRichEdit::OnURLClick(NMHDR *pNmhdr, LRESULT *pResult)+ H4 p1 q6 Z% L) v$ |3 t
{
& W2 y3 ?8 f" hTCHAR LinkChar[512];
8 L% B8 t$ G/ A! ]& ]. d( _  @ENLINK *pLink = (ENLINK *)pNmhdr;
; s2 F  g( [9 ^4 rif (pLink->msg == WM_LBUTTONUP)
* V0 Q0 Y1 s7 o' L4 W. J& o8 E: q8 F{
7 b( _2 V! H/ zSetSel(penLink->chrg);//这是链接的文字范围
# W: b$ _1 G" g1 {: S( |+ rlong Res = GetSelText((char *)LinkChar);//这是链接文字
& f# _" b6 j6 L/ K/ W: W1 {, ?                  //后面是你的处理过程
5 i9 x. c" b6 d$ C6 @- j# }' L                  ......
( |4 n1 z7 h8 {! p. m         }2 z1 q' O* t% ~* P7 M3 D
}
: s" v1 z0 d% @6 o- Z  g; _* f; y  u. z9 C
b.插入位图
7 P$ K  H7 O) U5 F: Y3 Vhttp://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/
6 Y; u$ C* U: j3 g0 phttp://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/4 f2 v4 o" X4 q0 h0 R" [% L. X
  g2 w! H! C# P  L+ f, E
自定义在RichEdit中插入对象的图标8 U, K* I( O7 V: k. W
http://www.blogcn.com/user3/jiangsheng/blog/1319738.html) g  ^2 ]0 f3 z) J3 R1 |& c$ {
方法基本同Knowledge Base文章Q220844 HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control8 r# n' R/ p( m- v0 I& n  H
只是在最后插入之前调用一下IOleCache::SetData,用一个HGLOBAL作为参数,HGLOBAL里面的数据是一个METAFILEPICT结构,包含自己提供的图片
) N- k) H( C8 p+ i: m9 G- C- n
; }; Z/ X3 [% B9 q- m# E使用CRichEditView::InsertFileAsObject就可以插入图像。VC++带有一个例子WordPad。( W8 ?- g9 e& ~4 P
另外可以参考“Insert any HBITMAP (Bitmap) in your RichEdit Control”(http://www.codeguru.com/richedit/richeditrc.html)。
/ n  P1 V, w; s+ r8 V' m7 L) k$ J" R" Z7 \7 J% u9 Z/ c' m( t
c.显示GIF动画
2 n0 r+ O- J- Y9 F常用的是通过qq的imageole.dll(也有用Gif89.dll的)
9 Q! L' c% y$ J3 E1 w  Lhttp://www.xiaozhou.net/cooldog/blogview.asp?logID=82
% h- W: `$ ]# M  I# [http://www.codeproject.com/richedit/AnimatedEmoticon.asp
. M6 ^  w2 r! j+ L2 P0 D2 c
% i7 {; t9 I. i: \0 F9 c在richedit控件中插入动态GIF (Native C++版)
; o. m" e1 ]7 R* i8 Y8 n0 ]7 b) Jhttp://blog.joycode.com/jiangsheng/archive/2004/12/15/41209.aspx
& O* P' s; s* y( V% q0 J( h" r' r2 w
d.IRichEditOleCallback的使用
6 N2 X5 z5 x' H% ]8 uhttp://61.186.252.131/Expert/topic/905/905844.xml?temp=.8379022
, Z& u( n; u0 o& S
7 V1 V/ _7 E( v1 D, K+ o类似 MSN 信息发送框的制作(上)" @, h& b" s5 D
http://www.vckbase.com/document/viewdoc/?id=1087
3 X9 u" W5 u" W  h) I) T6 F内容包含:实现右键菜单,图片插入,读取/写入RTF格式字符串
  Y  |  l4 |1 k/ k7 u
8 r' G: p7 k' E8 d/ M自定义 CRichEditCtrl 控件2 }. B) Z. r1 n5 l
http://www.vckbase.com/document/viewdoc/?id=328
- C0 F# f! M# P0 [5 Q, F内容包含:鼠标右键消息,消息映射,字体变换$ B; j* W$ G# G. r; g

6 D0 b  F, j4 Z$ i7 NPS.richedit控件升级到2.0后,先把字体设为楷体,输入汉字没有问题,但输入字母时,字母自动跳转为Arial字体,而1.0却没有这个文题,仍然是用楷体显示字母
+ M, H$ G7 J7 t# k0 N7 h是一个专门的设计 Dual-font, Smart font apply, 参见 http://61.186.252.131/Expert/topic/913/913807.xml?temp=.3753778 & w' ^' u" ?) ]5 a( g
----------------------
3 H% g7 ~$ F! f3 c1 r比我想象中还要花时间,所以最后潦草了点,见谅
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-5-2 08:55 , Processed in 0.020286 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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