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

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

[复制链接]
发表于 2006-12-11 14:36:01 | 显示全部楼层 |阅读模式
一.常见问题9 K1 c# X4 k4 b2 Y2 W
a.可以编译,不能执行的( s- r: g0 Y: a0 G! l) C' f
AfxInitRichEdit();
; v& t  K* n) g8 y& N& \; }1 m
- n5 ^8 ~1 Z' v% }  Cb.升级默认的Riched版本(默认的有一些bug),如5 r" c9 z7 s) J) M* L  D9 |2 u0 L
可在InitInstance中添加
3 |& s" _( X- H6 ^% v) wLoadLibrary("RICHED20.DLL") + t0 Q0 f/ E& g; _
最后注意 FreeLibrary
4 ~6 P# z8 l( u( ^9 t6 O8 F$ O
2 p. [" S, o3 C. @如果是CRichEditView基类的可用3 P" O# @8 d( p( p1 S  e- _
BOOL CXXXXXXView::PreCreateWindow(CREATESTRUCT& cs)
' H9 f3 W$ A$ K; u) e: A3 Z* m{( K" h+ g; _1 |$ D- E! w
//装入rich edit version 2.0
) W# w$ L1 \( M8 nif (LoadLibraryA("RICHED20.DLL") == NULL)
) Q# |$ q' N2 \0 @1 A4 ?{
+ g2 m  w# h7 c8 Q3 s* DAfxMessageBox(_T("Fail to load \"riched20.dll\"."),MB_OK | MB_ICONERROR);+ [% C$ Y, P8 `/ e
PostMessage(WM_QUIT,0,0);
0 [- L# s/ E- K( `return FALSE;  ]1 G# K: t5 s
}6 M, ?5 H4 V4 x
" J$ }+ p" X2 w, p5 {' [* D: Z/ N
m_strClass = RICHEDIT_CLASSA;//for 2.0 class& Z" ?6 w& }4 }% `8 C& C
3 w) b9 i2 ^) P; L
return CRichEditView::PreCreateWindow(cs);  |3 D) H7 [' O+ f
}" _5 E; C# [* u% A! g2 y4 a

# b3 Z0 t6 r+ O& Jc.最后追加行8 F4 s8 ?( m$ ?3 \1 J
richeditctrl.SetSel(-1, -1);
% u: u0 _$ H+ T9 Iricheditctrl.ReplaceSel( (LPCTSTR)str );6 w/ N/ l6 J8 m7 T6 ^

. Z4 X) x$ A5 q# _5 M2 b, i5 C/ Ld.字数限制
2 U* Q. d: M' p/ @# zCRichEditCtrl::LimitText(long nChars)
9 `$ G+ P2 @" h( @3 W3 h9 m' }; M) K1 ^, e
e.换行切换/ B8 Q9 m; q7 J" u, R- r7 K
CRichEditView的OnInitialUpdate()函数中加入下面两句:, p) I. ?9 ~5 P/ E$ N; J! M
m_nWordWrap = WrapNone;- x3 Q! O; d+ a, v9 V7 U& P9 x# J
WrapChanged(); / e  X4 [* ?: P/ I5 ]3 ^
WrapChanged实际上也是调用
& N. I/ d- D* N' @. d! d/ k" `ctrl.SetTargetDevice(NULL, 1); //m_nWordWrap == WrapNone+ S) Y0 r  B! i! ^  \  W, x3 F
ctrl.SetTargetDevice(NULL, 0); //m_nWordWrap == WrapToWindow: F1 {5 S4 c2 l9 `, p
还有不常用的 m_nWordWrap == WrapToTargetDevice3 O5 h& `7 h" [1 J+ ~( D
ctrl.SetTargetDevice(m_dcTarget, GetPrintWidth());2 l/ r* ]' I% q# q
如果是在Dialog中,可使用SetTargetDevice,注意在属性里面加上want return
- z' E8 p  b8 ~" E  v* @
9 O, t7 n% E8 C. O) Sf.有时候不希望带格式的数据粘贴,可通过PasteSpecial选择性粘贴) S9 `6 e) T! ~0 W
pmyRichEditCtrl->PasteSpecial(CF_TEXT);+ T  a6 V3 S: l5 z
, C/ Q% b# n, P9 k6 k! o9 L! B3 Q
g.随着输入随着自动滚动条滚动到最后一行
6 V# W. S% E9 m5 B* W) X! bint nFirstVisible = pmyRichEditCtrl->GetFirstVisibleLine();, D* R" t! e6 c8 e( G3 n
if (nFirstVisible > 0)
% @/ `& Z' p; l! E# G" P% P" M" J{" h: m/ s& \; ?' I& i3 H- V6 r
   pmyRichEditCtrl->LineScroll(-nFirstVisible, 0);
% x. W& q" I9 Y# n3 i}
" j, _* \1 U: T' o$ N. T& |6 y! r- Q3 f+ L6 O* [6 _/ ~
m_cRichEdit.PostMessage(WM_VSCROLL, SB_BOTTOM,0);2 f! o9 {$ X( `5 R
  L( p- C$ p! E% T: i& v
: S8 Z# G6 |5 F& Q0 x
h.设置UNDO的次数(只能用在RICHED20以上,即默认不支持,必须升级)
, e+ ~* K  Q# ?9 B: G) W2 R$ TSendMessage(EM_SETTEXTMODE,TM_MULTILEVELUNDO,0);9 o& i+ B2 Q4 V1 v: W
TM_MULTILEVELUNDO 支持多取消(默认值).可通过EM_SETUNDOLIMIT设置最大次数
7 M  ]$ B8 l$ A; S! C$ dSendMessage(EM_SETUNDOLIMIT,100,0);
- E- D6 @$ w8 M4 d# {6 V  v) @# @. E+ p" w
i.响应OnChange
: L( Q, I+ |0 A5 JEM_SETEVENTMASK 设置 ENM_CHANGE
4 ^1 l, v+ ]" x3 M- w- H% Blong lMask = GetEventMask();3 }& X6 F! t6 x4 U
lMask |= ENM_CHANGE;( j' |- K, v: B7 s0 j+ l
lMask &= ~ENM_PROTECTED;
- N  s* ]+ ]; V' ~  ~  Q: Z6 GSetEventMask(lMask);
; h( j8 M$ `( g7 b* u) q
, I$ [+ n! z. o( m; k* L9 ij.设置只读
4 [, _* q8 F5 {$ w6 c, FCRichEditCtrl::SetReadOnly( BOOL bReadOnly = TRUE );
& K/ b0 p4 ?  T9 t' C+ m3 W0 T通过设置PROTECTED实现选中的文本只读,参见1 G2 K# X, ~8 B6 k
http://www.codeguru.com/Cpp/controls/richedit/article.php/c2401/# j( s! e  Y$ t9 l( B
1 X9 o. Q+ Q- L4 ^, E1 K1 _( M& K
二.函数应用
7 X9 l# S# [5 G  W# Da.设置字体(主要是通过SetSelectionCharFormat)
. \9 y- a7 f8 H+ k! {9 {CHARFORMAT cf;
5 I/ P% r. c+ [4 Q$ lrich.GetSelectionCharFormat(cf);( T: S% D+ I* L6 F% j
cf.dwMask|=CFM_BOLD;% e! X8 [; }' i: C% G
cf.dwEffects|=CFE_BOLD;//设置粗体,取消用cf.dwEffects&=~CFE_BOLD;
2 J8 D. p; {% O! |- P* h' lcf.dwMask|=CFM_ITALIC;
' V1 V6 M" v) A; J% a5 G: C3 W& mcf.dwEffects|=CFE_ITALIC;//设置斜体,取消用cf.dwEffects&=~CFE_ITALIC;
4 i$ R: P% _3 h& B" @3 p0 Lcf.dwMask|=CFM_UNDERLINE;  \- z) [" C: O0 }5 T+ A$ U# i
cf.dwEffects|=CFE_UNDERLINE;//设置斜体,取消用cf.dwEffects&=~CFE_UNDERLINE;/ h6 v  \2 Z4 P1 S: ~
cf.dwMask|=CFM_COLOR;
  r; z. @) K7 r! V" f/ X( ncf.crTextColor = RGB(255,0,0);//设置颜色
& N4 ]" C2 t8 S% ~) \cf.dwMask|=CFM_SIZE;3 s7 M' e: u$ ^5 t3 w
cf.yHeight =200;//设置高度: @. t( P, `! _+ d3 x& e3 X
cf.dwMask|=CFM_FACE;% |3 b' f% P  V
strcpy(cf.szFaceName ,_T("隶书"));//设置字体) Q+ c7 m; E6 H8 _2 d' D
rich.SetSelectionCharFormat(cf);: b& c* @1 l) s" M5 R2 Q
3 U5 G: U- O' ?$ ?" \
b.设置字体的行间距
$ B4 [( N6 ]3 q9 P- W9 O: C0 v: Y要用richedit2.0以上( h9 w, D7 P. e% `- b
试试
/ n* `6 P. x. _$ B  X8 ^- }; e9 M/ yPARAFORMAT2 pf;
8 ^. R& K3 M. o) Ipf.cbSize = sizeof(PARAFORMAT2);
2 _9 \; f0 o: H) C, i9 Jpf.dwMask = PFM_NUMBERING | PFM_OFFSET;7 f; Z' ~7 M) x3 g5 Q
pf.wNumbering = PFN_BULLET;//注意PFM_NUMBERING
. s. @! _! d! e) ^* V# Wpf.dxOffset = 10;
8 [( {; @2 ~- LVERIFY(SetParaFormat(pf));
7 X+ B+ d( H$ e5 V5 H常用的dwMask有! K2 e/ W" Z' T& V* |: z
PFM_NUMBERING 成员 wNumbering 才起作用,项目符号,默认用PFN_BULLET& ~4 p  v" Z! T3 r- l1 E- K7 j
2 使用阿拉伯数字 (1, 2, 3, ...).  
3 F  F# O8 G4 E. R5 {8 s3 使用小写字母 (a, b, c, ...).  ( Z: H$ m3 \5 H* L
4 使用大写字母 (A, B, C, ...).  
1 O/ \( H  |5 u! z) c$ ^7 {5 使用小写罗马数字 (i, ii, iii, ...).  
2 q4 N. k% e' \( i: c' L6 使用大写罗马数字 (I, II, III, ...).  
# g' W+ V+ `  ^! o7 自定义,字符见成员 wNumberingStart.  
5 g, H3 X! t' I2 Q; O1 ZPFM_OFFSET 成员 dxOffset 才起作用,缩进,单位twips1 B! M4 k, T' I4 K
PFM_STARTINDENT 成员 dxStartIndent 才起作用,首行缩进: f+ X/ F" b3 S" o. k+ Z9 F
PFM_SPACEAFTER 成员 dySpaceAfter 才起作用,段间距" J  g: a; f& V8 i8 q
PFM_LINESPACING 成员 dyLineSpacing 才起作用,行间距
4 t: m7 ~; I" h# {7 b  A' J" G. s$ Z. A
c.设置CRichEditCtrl(2.0)背景透明
/ y" p$ E& n2 N1 z% R  E* m" f- mlong style = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);0 D( C; W) h- s$ c
style &= WS_EX_TRANSPARENT;' Q; P# L) f' {
::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, style);
5 f) a* i# {% J  W7 `: d或 CreateEx,然后把WS_EX_TRANSPARENT样式加上
' f* s8 {8 L, _: z
3 ^: U' ~3 x1 e' K6 pe.得到内容有三种  F1 B/ a0 r& `: C( Y+ j
1)GetWindowText
) p  D. ^0 G  ], o2)使用EM_GETTEXTEX( g, J- T/ T% f4 Z* r
GETTEXTEX gt;
. ^- t' n& E) x/ ?gt.cb = 200;6 E) t) Z$ R2 r
gt.flags = GT_DEFAULT;( I$ `! s9 x/ ], c
gt.codepage = CP_ACP ;
; m' c" D- j' _gt.lpDefaultChar = NULL;
" ~: {) N. }) P" Fgt.lpUsedDefChar = NULL;; d8 @0 V- T% n" ^' X
SendMessage(EM_GETTEXTEX,(WPARAM)&gt,(LPARAM)text);! y4 W6 V4 N+ v! W4 {6 W
3)StreamOut(主要用于RTF等格式输出)
5 |3 j& a& E" O  ^: [static DWORD CALLBACK
7 N4 L6 ]2 _7 _( g6 d: S4 pMyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)0 K1 A- h9 p$ }4 \4 k
{
% w. |; X( C1 B, H* m# A+ `   CFile* pFile = (CFile*) dwCookie;
$ N1 ~( t" j. G7 H* q, {" C6 T- B! }" h0 b1 P
   pFile->Write(pbBuff, cb);
1 L$ c8 n% [2 g8 T" t- T) h; A   *pcb = cb;
1 {; `* L! k9 b% v! _, }; V$ z- i3 k- H- @
   return 0;
! ?* w5 n6 ^% L5 \) v7 r0 b}
, f/ r; ?+ U+ N7 H0 b( z7 t! l" D9 e( v

! G" O* G9 j2 D+ d1 N+ c* L   CFile cFile(TEXT("myfile.rtf"), CFile::modeCreate|CFile::modeWrite);
$ X0 h! B2 U. z, m   EDITSTREAM es;
6 ]8 }9 [% I) t   es.dwCookie = (DWORD) &cFile;//设置用例参数,以便回调函数调用( E& V- q7 C# R4 Q: H4 J
   es.pfnCallback = MyStreamOutCallback; 5 X- B  t2 I8 b* ?$ K7 p
   pmyRichEditCtrl->StreamOut(SF_RTF, es);
& k0 g# F5 r, e读入可以此类推,SetWindowText,EM_SETTEXTEX,StreamIn
# ?0 J, a: t; U2 R  r/ |$ d. E" b1 l, U, T) g. b) S0 m0 C
f.查找字符串1 B# K; x/ D6 z( ]
FINDTEXTEX ft;
* [* Q% D' K' zft.chrg.cpMin = 0;
  R& X* _9 t+ O% C+ q- g5 Zft.chrg.cpMax = -1;
) L& \3 f2 F6 T( q; zft.lpstrText = "|";
* {6 X1 @1 i3 Clong lPos = FindText(0, &ft);$ \" b& l, F2 T4 b

. D/ Y/ d  N. ?, C+ m, [0 X8 o# g如果要继续查找,修改cpMin,如: j0 C" v- ?, X& {# A: A
int nCount = 0;
  D9 N% L7 w" V9 M. p( qdo, ]2 M/ A6 q6 v# ]5 P& p
{
6 P, l; c; ^. @7 T- H9 f3 d: f( B long lPos = GetRichEditCtrl().FindText(0, &ft);
! C2 @" h& V3 `* a" ^ if( -1 == lPos) break;. n% n5 h! Q% K% H* ]; L9 ~& q! F# n
ft.chrg.cpMin = lPos + strlen(ft.lpstrText);# T/ \( O, Z' \; x3 a
++nCount;
8 G' l9 U  P  |( T}while(TRUE);
8 p0 e3 U& Y  `6 d% t* [" ~4 U+ j, V4 v" V, S0 y+ K
g.以Html格式保存
3 k% q$ e* C0 c目前做法可先转为RTF格式,再通过RTF-to-HTML Converter
, T  [0 d% E$ }( j+ Shttp://www.codeguru.com/Cpp/controls/richedit/conversions/article.php/c5377/
( r8 k4 L$ H7 p0 I% ]& P  J: k5 U. s7 B+ x; V# u& s
h.重载OnProtected函数得到对应的消息,如粘贴等
* w/ S6 h; ~9 Dvoid CMYichEditorView::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)1 g9 T% c5 m0 b& k
{
: X+ R1 W1 [0 D2 F: n7 A7 m ENPROTECTED* pEP = (ENPROTECTED*)pNMHDR;) [2 N1 B9 z- q/ {6 e0 A6 V0 d
9 @6 o7 v! v7 ]. ]3 @
switch (pEP->msg) {
% [% J" U% C9 N) d6 G case WM_KEYDOWN://按键,判断pEP->wParam
, s% E( s9 |5 Z+ B case WM_PASTE://粘贴& T: W/ L5 K7 b, ?
case WM_CUT://剪切7 ~) c& O2 w# K3 u, D+ @
case EM_SETCHARFORMAT:+ L1 {3 Y6 i6 |$ U  o
default:, S# A) k- a0 h' b5 W
  break;- c8 D0 B: M" J2 c" B2 D  d, d7 X
};/ m1 l0 I' p+ P$ Q6 V
6 t: t) o" L5 t1 D9 m
*pResult = FALSE;  e' T1 X' r1 I  C" d
}. }. G0 w( {: r9 s5 {: M! p- ]
4 l5 n# }2 x. g; Q1 e5 x
三.聊天常用  
; E: u6 ?/ }  v8 Z! La.LINK 链接功能) D8 H9 b" d4 L, X* e. ~
1.  LoadLibrary(_T("Riched20.dll"));
9 w. |; w2 X) [* x; d2. 创建RichEdit2.0控件# w  x* C1 T& C7 N! Y
CreateEx(0, _T("RichEdit20A"), NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP' n9 D; _( M, E. x6 F2 }
|ES_READONLY|ES_WANTRETURN|ES_MULTILINE,
2 |* Z9 Q% S. a8 A0 b* s% T          rect.left, rect.top, cx, cy,/ _# @. j. l( O5 a- f
  pParentWnd->m_hWnd, (HMENU)nID, NULL);7 o( s! m( T5 V
3. 设定选中的文字为链接显示
" ^) Q" U& i0 \1 \  w' y" e$ ?CHARFORMAT2 cf2;; T' Y. g0 R0 j4 V) @
ZeroMemory(&cf2, sizeof(CHARFORMAT2));//
. B) E+ x6 G( l# U/ M3 R; U' Xcf2.cbSize = sizeof(CHARFORMAT2);
% I% k. x9 A  mcf2.dwMask = CFM_LINK;& O* M$ a7 V/ c" A3 u
cf2.dwEffects |= CFE_LINK;
% b- ~1 S- O( am_cRichEdit.SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);4 A; Q# x1 |6 O, t; @# `. k4 E
4.支持链接的点击响应
+ l+ T7 E; N3 r' r$ D( O2 @. l( a9 tm_cRichEdit.SetEventMask(ENM_LINK);
) b4 N, v+ ?7 @( M5.响应链接的点击EN_LINK$ @% ^, B' V* Q2 n; q4 T8 v
. n, H! Q4 `9 n0 v, n0 Z% {4 Q
BEGIN_MESSAGE_MAP(CMyRichEdit, CRichEditCtrl)
/ X; R( L9 g* L! X4 ~; c5 RON_NOTIFY_REFLECT(EN_LINK,OnURL)
* h% a. e, [: y5 k) T- G  jEND_MESSAGE_MAP()
# p) l/ |# K- D1 E8 r- i( Y......2 Y8 A6 l3 ~# @% G/ S: x
, }7 [( Z' N9 C4 F7 P9 B0 Z- K& t
void CMyRichEdit::OnURLClick(NMHDR *pNmhdr, LRESULT *pResult)
1 ^, G$ C7 N7 O8 c3 k{
" v7 G3 a9 }" A1 K; bTCHAR LinkChar[512];7 L0 m; L7 [6 h0 q  M
ENLINK *pLink = (ENLINK *)pNmhdr;
: P+ _6 {2 z& {8 i( T9 S& iif (pLink->msg == WM_LBUTTONUP)2 ]. N7 _1 P9 ]! n2 Z, b5 \! g7 e
{
' x+ e! e0 g, a/ \) @+ ^& J2 U; aSetSel(penLink->chrg);//这是链接的文字范围
5 T! w) r9 B4 ^7 @/ ^: K2 slong Res = GetSelText((char *)LinkChar);//这是链接文字' r, q1 I% R/ @4 n
                  //后面是你的处理过程
1 I+ \' y; Q& k* x                  ......
7 L. h, `1 |* J3 R         }
5 \  L7 A8 P; O- N$ y! [+ u}! I5 ]8 J, F3 k6 I
& H. ~! ]' s. o* {) @5 P2 r' c
b.插入位图
' v1 l+ h4 x) i& o5 E( Nhttp://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/, f. k8 l! B  v3 _7 |8 C
http://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/
: j) c' G" B! Y  g4 k
1 `2 P: {/ A" C1 D+ [7 f自定义在RichEdit中插入对象的图标* v- y1 v  D4 a) r3 [5 h
http://www.blogcn.com/user3/jiangsheng/blog/1319738.html8 \  M- h& Y7 D( s- `$ O
方法基本同Knowledge Base文章Q220844 HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control* _/ ]. _; w* u
只是在最后插入之前调用一下IOleCache::SetData,用一个HGLOBAL作为参数,HGLOBAL里面的数据是一个METAFILEPICT结构,包含自己提供的图片
0 v" T1 ~4 c( |; a; c3 L- ]  g- B3 [! L' }/ P' K
使用CRichEditView::InsertFileAsObject就可以插入图像。VC++带有一个例子WordPad。
2 F3 p% U3 ^+ {- Q8 {另外可以参考“Insert any HBITMAP (Bitmap) in your RichEdit Control”(http://www.codeguru.com/richedit/richeditrc.html)。
# l2 u* T# @. C" o( Y9 `
: S5 R6 `$ ]4 ?5 L  ]( fc.显示GIF动画
- ?  m6 K( j# ^* Q# Z常用的是通过qq的imageole.dll(也有用Gif89.dll的)
" w) a) v# p2 d: b- vhttp://www.xiaozhou.net/cooldog/blogview.asp?logID=82$ B! w* M- S5 ~; Q4 s. L  K
http://www.codeproject.com/richedit/AnimatedEmoticon.asp: l9 e5 Y! Z- s  M! h6 n

3 _7 k/ z% \  s5 w& P在richedit控件中插入动态GIF (Native C++版)
8 E9 k0 V; E5 R, f2 hhttp://blog.joycode.com/jiangsheng/archive/2004/12/15/41209.aspx6 _1 |8 M# k# q, E3 M3 T
8 w; Y) ]% |0 H5 M! \1 q
d.IRichEditOleCallback的使用
; E+ H/ d3 j2 y+ E2 n4 d+ h* zhttp://61.186.252.131/Expert/topic/905/905844.xml?temp=.8379022$ N* m! s5 [6 f' T

3 ]  v, b5 E- i- v  j# y类似 MSN 信息发送框的制作(上)+ p2 S- D2 h4 M6 H, {. W  I% f: B
http://www.vckbase.com/document/viewdoc/?id=10875 q# H8 r8 r) B0 m1 y2 m
内容包含:实现右键菜单,图片插入,读取/写入RTF格式字符串
& n& n( G  D4 r% ]9 {. a" V1 ?* I9 m& k
自定义 CRichEditCtrl 控件
- x6 V2 N# V3 ^$ J, Thttp://www.vckbase.com/document/viewdoc/?id=328
6 \/ f( I& @  P内容包含:鼠标右键消息,消息映射,字体变换! x$ m4 O2 P9 @! J2 L% p
, I7 {. U/ T. V  L
PS.richedit控件升级到2.0后,先把字体设为楷体,输入汉字没有问题,但输入字母时,字母自动跳转为Arial字体,而1.0却没有这个文题,仍然是用楷体显示字母& z( w& G9 ?% O. M' d5 M3 x. U
是一个专门的设计 Dual-font, Smart font apply, 参见 http://61.186.252.131/Expert/topic/913/913807.xml?temp=.3753778 " s" z, w9 ~- Z2 @& B+ O! e
----------------------
* b* Z: D! L8 C" w) K* b7 U: p比我想象中还要花时间,所以最后潦草了点,见谅
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-6-18 10:28 , Processed in 0.018623 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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