|
|
一.常见问题. e5 y) s5 p3 M2 F% Q" G
a.可以编译,不能执行的
{# s5 i3 ?, D# N! L8 n0 B& |AfxInitRichEdit();
# ~8 w6 o" n. G1 d- z0 k' l, X
4 Y" Z1 B l& g" ~b.升级默认的Riched版本(默认的有一些bug),如 o( U! y8 O7 n6 j3 {
可在InitInstance中添加) n Q& t [" G, j+ q5 l/ ]; q
LoadLibrary("RICHED20.DLL")
% D7 X h8 W7 s. E最后注意 FreeLibrary
7 |) T% i7 w" U) J- H. s4 n8 ~! P; g: J% B6 s9 ^/ m B4 M; r8 c
如果是CRichEditView基类的可用/ R& K2 @9 u: ]/ o0 }: l9 b/ |3 Z
BOOL CXXXXXXView::PreCreateWindow(CREATESTRUCT& cs) c% o: g. e/ K7 ]9 ^1 Y) A
{
2 p) S3 H6 r; V" d9 D% V7 V2 V//装入rich edit version 2.0) u& a# t0 y6 V" _
if (LoadLibraryA("RICHED20.DLL") == NULL)
_& ~: _2 _5 k2 L# [% B: e; `{
; Z8 @0 k" X d. R0 C+ _AfxMessageBox(_T("Fail to load \"riched20.dll\"."),MB_OK | MB_ICONERROR);
; H: ~9 E; x. gPostMessage(WM_QUIT,0,0);
0 A s$ h- y9 }1 U+ R' kreturn FALSE;' U: y, u3 Y: y! s
}
% s: C, q5 x4 e$ @" I4 t) M L! h- X/ F' }. X
m_strClass = RICHEDIT_CLASSA;//for 2.0 class \! R5 x% c' k8 O* Y( u
e: e r9 o! \: t' p {& S' M" Y; Dreturn CRichEditView::PreCreateWindow(cs);
3 Q* Y" F1 |+ G# u9 p0 P}) B1 c% K: V1 R; K7 c! A
& P" _* O. {# M& yc.最后追加行
0 d ]6 j A0 Lricheditctrl.SetSel(-1, -1);
' _3 R: F- v" G+ uricheditctrl.ReplaceSel( (LPCTSTR)str );
& b- H! b5 Q! `: y9 g1 e) F3 k
2 }4 T2 X) {. d( f4 y9 `d.字数限制
) C; R5 y) _3 u+ p/ o% \ VCRichEditCtrl::LimitText(long nChars)
/ E* X6 r% v/ r9 I* s
* S$ P2 i& x V; [e.换行切换
/ {3 v# P& e5 w" DCRichEditView的OnInitialUpdate()函数中加入下面两句:/ k/ m3 X% G/ d% C. R
m_nWordWrap = WrapNone;: ]% s6 ]7 m( b j' ~: _
WrapChanged();
5 g1 Q# p4 S- N0 d3 [6 F4 \7 yWrapChanged实际上也是调用
3 r& _/ U- T* E+ h3 |! e1 Rctrl.SetTargetDevice(NULL, 1); //m_nWordWrap == WrapNone
3 v% v+ L- b& X' n0 T1 w- Ictrl.SetTargetDevice(NULL, 0); //m_nWordWrap == WrapToWindow
! ^- o( S5 P l7 K8 S& A还有不常用的 m_nWordWrap == WrapToTargetDevice
7 C' ^8 X' q7 M. s. g4 k+ {- Ictrl.SetTargetDevice(m_dcTarget, GetPrintWidth());! }6 j8 A& j+ s; N% O
如果是在Dialog中,可使用SetTargetDevice,注意在属性里面加上want return
, o2 P' j3 o: s# M5 q- ]- F$ v n4 Y7 G+ {
f.有时候不希望带格式的数据粘贴,可通过PasteSpecial选择性粘贴
/ ~3 w+ `; ^+ \/ Z) I# WpmyRichEditCtrl->PasteSpecial(CF_TEXT);; G* A' q4 g g# B& ~0 Y% c4 d
7 v: j& r& {, l( h) H4 o
g.随着输入随着自动滚动条滚动到最后一行
3 r% J* W( H4 A7 ^2 l. A9 Mint nFirstVisible = pmyRichEditCtrl->GetFirstVisibleLine();
4 f6 J7 W& P9 m7 Mif (nFirstVisible > 0)
. q' f" H) M1 ^3 [; o% ?# f1 o; R{: v. V: B: p e v% m( Y/ H/ ]9 t! |
pmyRichEditCtrl->LineScroll(-nFirstVisible, 0);9 X; v( d% s8 P/ N- V+ E
}! K1 ]8 f* d+ N1 m& h
或
5 g, v7 a9 m9 D ?- dm_cRichEdit.PostMessage(WM_VSCROLL, SB_BOTTOM,0);, l& \# }0 P5 ^1 \5 r5 `
& d' N, y N9 p% N* d+ i. i! c% X9 R
h.设置UNDO的次数(只能用在RICHED20以上,即默认不支持,必须升级)3 t6 F. m# U9 s2 A
SendMessage(EM_SETTEXTMODE,TM_MULTILEVELUNDO,0);
}- R0 i( x5 k0 ~) A, H7 nTM_MULTILEVELUNDO 支持多取消(默认值).可通过EM_SETUNDOLIMIT设置最大次数 6 e% ]% V2 a% K* d4 I# [- S- N6 U
SendMessage(EM_SETUNDOLIMIT,100,0);
' u. c( Z7 P" S0 a0 I2 m8 f# I9 f2 s7 U6 O7 o+ E6 {
i.响应OnChange
7 Q- V; l8 D1 VEM_SETEVENTMASK 设置 ENM_CHANGE % V4 n( k9 F9 l+ A- Q& p
long lMask = GetEventMask();' e$ b; W* I- K! }. B; S. X4 O) A% Z4 B
lMask |= ENM_CHANGE;
# ?" c" x6 a" ?4 e2 \: ClMask &= ~ENM_PROTECTED;, J; Z% d: B1 U H0 G* {, \& u! b
SetEventMask(lMask);" K1 B$ h8 M1 Z/ G \' a& U
. q/ b$ @9 W0 P* |; `; pj.设置只读
4 L3 R8 t% T* g2 b: rCRichEditCtrl::SetReadOnly( BOOL bReadOnly = TRUE );
( o) A$ g9 |% o4 e$ D通过设置PROTECTED实现选中的文本只读,参见( D- q( e& N4 D$ P9 k# a$ \
http://www.codeguru.com/Cpp/controls/richedit/article.php/c2401/- m# R# P8 H; G# z
- J: O8 _& h# x二.函数应用' I$ ^# n3 V, l5 M
a.设置字体(主要是通过SetSelectionCharFormat)7 ?: A0 H3 d' N4 l6 [' Q8 v. h
CHARFORMAT cf;3 }$ B% [! v& p6 N& R# }
rich.GetSelectionCharFormat(cf);
8 o' q/ B1 x$ i; P: q) _cf.dwMask|=CFM_BOLD;
5 }7 l3 W( ]$ l* }, scf.dwEffects|=CFE_BOLD;//设置粗体,取消用cf.dwEffects&=~CFE_BOLD;
& v. N+ ?1 \) tcf.dwMask|=CFM_ITALIC;
$ Q# I% ?: F0 A* U1 T8 fcf.dwEffects|=CFE_ITALIC;//设置斜体,取消用cf.dwEffects&=~CFE_ITALIC;
6 d: k* q4 N4 o, c2 u* H+ Jcf.dwMask|=CFM_UNDERLINE;
( a$ A8 T% k. P3 C4 {cf.dwEffects|=CFE_UNDERLINE;//设置斜体,取消用cf.dwEffects&=~CFE_UNDERLINE;
6 i0 O6 f* [; a$ Y Q9 A6 d- p; L' `cf.dwMask|=CFM_COLOR;% T7 w, U3 C& e% l
cf.crTextColor = RGB(255,0,0);//设置颜色0 f# s* R3 d6 A, F1 Y1 _
cf.dwMask|=CFM_SIZE;
' l3 i5 I/ n) z! }2 mcf.yHeight =200;//设置高度3 ]9 Y& v3 h1 P
cf.dwMask|=CFM_FACE;, J: m: w) K7 @
strcpy(cf.szFaceName ,_T("隶书"));//设置字体
! i ]3 e/ d3 v; Qrich.SetSelectionCharFormat(cf);
6 K0 n% J# W# T6 R+ L0 w* C% h3 m+ |8 r# O. X+ f9 f
b.设置字体的行间距
# ~) Q5 y' k0 L) Q要用richedit2.0以上, H3 \6 F. S/ V) g1 _
试试
6 e' c @! o( j) t, r3 ^PARAFORMAT2 pf;
4 j' k) J4 [3 f' Epf.cbSize = sizeof(PARAFORMAT2);
% I/ E) O/ f" y% V6 Zpf.dwMask = PFM_NUMBERING | PFM_OFFSET;# Z4 |; x4 z5 N% j6 L1 o j! F
pf.wNumbering = PFN_BULLET;//注意PFM_NUMBERING
: W: i8 o- y8 M! @3 Opf.dxOffset = 10;- |' ]! O0 e# R A! ]
VERIFY(SetParaFormat(pf));
4 F6 L5 S' \/ Q0 Z8 ]7 _- u- u常用的dwMask有( h* R- R, }. u/ y
PFM_NUMBERING 成员 wNumbering 才起作用,项目符号,默认用PFN_BULLET6 w( ` z; F4 U! x: Y5 f8 }
2 使用阿拉伯数字 (1, 2, 3, ...). & g# n5 O) C! C$ j6 S) J% O
3 使用小写字母 (a, b, c, ...). 4 _4 D' V. |+ K6 F. h
4 使用大写字母 (A, B, C, ...).
) o$ E8 X9 D0 d4 `8 O$ X5 使用小写罗马数字 (i, ii, iii, ...).
0 {9 q+ R: h* B; [6 使用大写罗马数字 (I, II, III, ...).
, }) s$ B9 H: z% n4 A4 ]7 自定义,字符见成员 wNumberingStart. - r2 v7 |/ O/ V
PFM_OFFSET 成员 dxOffset 才起作用,缩进,单位twips3 ]" N( U* G. U2 _3 U% a' ?7 g- F
PFM_STARTINDENT 成员 dxStartIndent 才起作用,首行缩进7 ~" w* F8 Q9 T( W# {
PFM_SPACEAFTER 成员 dySpaceAfter 才起作用,段间距
6 F9 C; B. Y0 {& zPFM_LINESPACING 成员 dyLineSpacing 才起作用,行间距
$ t; E" `, W2 d0 }3 t" |7 S9 t% K3 k; [1 j( W" J. F6 k# }
c.设置CRichEditCtrl(2.0)背景透明
$ L+ s; [, e2 |long style = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);6 A$ l6 m/ C* W8 q. q
style &= WS_EX_TRANSPARENT;4 I1 V: I9 u! N |1 _' K* ]0 @
::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, style);! i; C+ r) P9 e* ]; E3 l8 J9 p& J
或 CreateEx,然后把WS_EX_TRANSPARENT样式加上
8 r3 l1 ?! j( c. a1 M' e
2 c( m. Z! K3 p' Y, De.得到内容有三种- }: M* V y9 E8 @! Q
1)GetWindowText% z \8 a' H0 v0 x& p! P" s
2)使用EM_GETTEXTEX, L4 Y8 J1 V5 e: \; u
GETTEXTEX gt;
# X/ t3 [- S- }7 ggt.cb = 200;7 p8 f# ~$ G3 b u" F' a
gt.flags = GT_DEFAULT;
& |3 o5 l% Y6 L( z1 V5 K& Mgt.codepage = CP_ACP ;1 z9 `; S1 n) X2 d
gt.lpDefaultChar = NULL;
& e' b+ z7 S0 q7 `gt.lpUsedDefChar = NULL;" _* W5 k2 s/ [5 Z. t2 P, G* p
SendMessage(EM_GETTEXTEX,(WPARAM)>,(LPARAM)text);2 ]+ v! k! @. i
3)StreamOut(主要用于RTF等格式输出)2 v- s- E6 b; f% e) O) h
static DWORD CALLBACK
5 j/ A, }. j! e8 @2 J2 N+ zMyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
& Q' q4 O5 g0 L. v! m{0 J6 n6 c z. l7 s. x* s* z1 P, [
CFile* pFile = (CFile*) dwCookie;
6 T, `2 ?1 S6 B# A7 H2 y: J" ?3 }# E0 a+ K p7 Y) M6 \" D5 k
pFile->Write(pbBuff, cb);
' _. B7 V1 p$ i0 d% W4 s *pcb = cb;
/ i, S4 ^! C! H" B q" i8 Z
& o" e* H$ N+ P- T o8 i% A return 0;1 e Q2 Y. z# j& b& d
}0 p* r. j* b& u, N8 m6 X3 @: o8 j7 F7 y
3 I0 D5 C% w! T K. o5 ^( R0 T, b% t+ Z3 a1 v3 v+ I* G
CFile cFile(TEXT("myfile.rtf"), CFile::modeCreate|CFile::modeWrite);' A; {8 z6 }2 ]% ^9 w, b# R
EDITSTREAM es;
4 e8 d( o1 n& ]0 Z& q es.dwCookie = (DWORD) &cFile;//设置用例参数,以便回调函数调用
' H3 T( K, t- F% \ es.pfnCallback = MyStreamOutCallback;
5 `: l9 s" v j3 | pmyRichEditCtrl->StreamOut(SF_RTF, es);( D6 V2 e5 m0 k6 b
读入可以此类推,SetWindowText,EM_SETTEXTEX,StreamIn4 b- e' U- m7 k& Q! ~2 c
- x! v$ r: _0 i. x. B6 D: G ~9 |# E+ Z
f.查找字符串0 L& t1 ^2 |, {% X, [7 n
FINDTEXTEX ft;7 s3 ~1 o& W3 O* V) U8 i
ft.chrg.cpMin = 0;$ S- w' {+ j, ~
ft.chrg.cpMax = -1;
& p6 m' }" M9 ^, Sft.lpstrText = "|";$ \$ l* v& l8 X" S3 o2 C s
long lPos = FindText(0, &ft);
, q" `) s O! k( e9 g) S. M% G$ e! t, K, O3 w1 Z
如果要继续查找,修改cpMin,如
+ _, }( _ e8 }. k( A" u! gint nCount = 0;- H. _; `8 u! T: h
do
/ G: J) t2 y! k, k% v0 I{ j$ R3 P+ s1 Z8 V, ?, N/ X1 G
long lPos = GetRichEditCtrl().FindText(0, &ft);
5 J, I: |; `- m2 t% h if( -1 == lPos) break;, j/ ?) q$ R9 L2 N g
ft.chrg.cpMin = lPos + strlen(ft.lpstrText);! Y9 _8 i. T( I
++nCount;" y& v, {/ N: h" d* ]4 T
}while(TRUE);2 W2 B- }$ |7 ~* O% {& U
1 U4 k2 @ q* {4 s7 O' Jg.以Html格式保存9 A9 R0 V+ D* N( X0 X. \) S- `
目前做法可先转为RTF格式,再通过RTF-to-HTML Converter
7 l* c' O9 L: F J3 V" @http://www.codeguru.com/Cpp/controls/richedit/conversions/article.php/c5377/
; f# m2 c/ s! d3 x) V _$ o( C6 {$ k+ a; F. X$ S- C. l6 E) `
h.重载OnProtected函数得到对应的消息,如粘贴等
+ r6 \6 M( [2 I. o, \2 \void CMYichEditorView::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)
3 Z% ?: E! G) i3 r ~' T{+ }: T' f w: z/ f) w4 Y6 ]4 E7 D
ENPROTECTED* pEP = (ENPROTECTED*)pNMHDR;4 f3 `2 H A- s+ O* k$ N
/ T& Y3 C1 f+ `7 l% h0 q
switch (pEP->msg) {6 v7 _ h. @+ T( @
case WM_KEYDOWN://按键,判断pEP->wParam
0 n5 `! L2 s! D: x9 M case WM_PASTE://粘贴& v5 d/ o9 l2 M# d# Q) M: M
case WM_CUT://剪切2 O! m6 X; V9 h9 }" C
case EM_SETCHARFORMAT:% I/ D" b i8 t9 l6 V4 u& y) K
default:8 [2 V4 ?, x9 A3 m* M/ P
break;3 I! K! e3 w+ B- G& H3 D
};8 P8 T s: Z: _6 Y9 [7 ]
* ~/ p* p' g0 R- E
*pResult = FALSE;+ X+ I( W+ s, k& i3 A, B. L
}
, U F* x1 T% D- V8 Q' i2 A, ~) O1 L1 X
三.聊天常用
# h1 J# ]8 N, j* o2 R. k% `. J3 C9 [9 Pa.LINK 链接功能
& z% [9 N2 t C q Z! M$ X! z; @1. LoadLibrary(_T("Riched20.dll"));
& L5 M+ C9 m/ l7 d1 p* L5 F2. 创建RichEdit2.0控件! s! Y1 G, X# I& p4 m: F1 w2 r: `) w6 @
CreateEx(0, _T("RichEdit20A"), NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP
! q- w1 u6 W. I: j. G|ES_READONLY|ES_WANTRETURN|ES_MULTILINE,
5 j# c5 E& x4 E7 c" q+ T. Z! V rect.left, rect.top, cx, cy,
9 F/ D% ]8 J2 L$ b: n pParentWnd->m_hWnd, (HMENU)nID, NULL);0 A% V/ _. }7 P0 Y
3. 设定选中的文字为链接显示 ^: d- g# i+ l/ d- A
CHARFORMAT2 cf2;% L: Z8 E" ]1 ]( M5 g
ZeroMemory(&cf2, sizeof(CHARFORMAT2));//& O2 S* x# U* t
cf2.cbSize = sizeof(CHARFORMAT2);9 P3 F1 `6 V: h0 D, Z% t9 `. q
cf2.dwMask = CFM_LINK;
( Y1 ]% z/ ?8 i5 I* X" q8 Zcf2.dwEffects |= CFE_LINK;
7 T' ~5 m' R# d; H5 C3 R- z# bm_cRichEdit.SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);2 J9 N* Q! x; v
4.支持链接的点击响应0 G/ m$ a, l; H) H0 H
m_cRichEdit.SetEventMask(ENM_LINK);: f% ]- n7 s# s
5.响应链接的点击EN_LINK
4 r" F4 V& t u1 H! L7 A. }' i# z
$ i" b! D, K# L" @/ J5 b3 j9 IBEGIN_MESSAGE_MAP(CMyRichEdit, CRichEditCtrl)' p" y( p! @8 h! d+ I
ON_NOTIFY_REFLECT(EN_LINK,OnURL)( B0 L, y: `' \9 |4 p9 q& o9 g
END_MESSAGE_MAP()
% T9 n$ |% v2 M/ y% b1 F+ w......
3 p* {6 E& S# d% ^, M' J4 A6 X* a$ h7 _2 C! @' G
void CMyRichEdit::OnURLClick(NMHDR *pNmhdr, LRESULT *pResult)
6 W5 @6 a9 t- K* @) ?4 Y: v{$ B& c; r+ L9 ?. v! G! \! Z9 O* e
TCHAR LinkChar[512];
* S0 b# g0 W1 S* W" o# uENLINK *pLink = (ENLINK *)pNmhdr;
* B- f3 Q+ [; }1 E8 Bif (pLink->msg == WM_LBUTTONUP)/ g* D' Q0 j+ q _. B2 B( V( e
{
4 M; O; E Q9 F& X$ z5 |6 N, }SetSel(penLink->chrg);//这是链接的文字范围& _6 f' g i ? z) @
long Res = GetSelText((char *)LinkChar);//这是链接文字
6 y! f/ h- \" U' R5 O. K //后面是你的处理过程( X6 |0 X5 f }4 Q7 W2 \1 Y
......# l) G7 `) Z* \* Y" C& u; z" _9 u
}3 f" s! m& ]: _6 E$ W
}
( `* L( L) l! F3 k1 y0 |! c2 m6 y# t0 Z* z$ O! {+ u
b.插入位图
) B- f$ `1 ^0 H4 Y3 lhttp://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/ H! M' d2 }3 ]) m
http://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/
8 Z1 w* f! L0 ?. w4 P7 |% f8 i! K- s. g& z: o8 U) g
自定义在RichEdit中插入对象的图标- y0 l! k8 {; l
http://www.blogcn.com/user3/jiangsheng/blog/1319738.html
4 x8 ]. I B4 ^( R. f1 ?' I方法基本同Knowledge Base文章Q220844 HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control
% b* p5 Z1 k: s$ x2 e0 E' s只是在最后插入之前调用一下IOleCache::SetData,用一个HGLOBAL作为参数,HGLOBAL里面的数据是一个METAFILEPICT结构,包含自己提供的图片' u$ L( w& @* ~
: ?0 [( `/ o4 _- c* N
使用CRichEditView::InsertFileAsObject就可以插入图像。VC++带有一个例子WordPad。( S6 v) { ^; I" G% G* B
另外可以参考“Insert any HBITMAP (Bitmap) in your RichEdit Control”(http://www.codeguru.com/richedit/richeditrc.html)。 ) Y9 Y& @& r- L- _$ q
% l& n; S# j/ x: o8 ?/ yc.显示GIF动画
6 t. Q& C4 o5 R$ Z常用的是通过qq的imageole.dll(也有用Gif89.dll的)
+ |6 T" X0 `1 w: \http://www.xiaozhou.net/cooldog/blogview.asp?logID=828 h0 e' U% f( J" W
http://www.codeproject.com/richedit/AnimatedEmoticon.asp2 y z9 }. q2 t2 L; c; B
' O/ A! ~& \( \: X3 T9 Z在richedit控件中插入动态GIF (Native C++版)# j8 k; V' }, }- p) c6 f
http://blog.joycode.com/jiangsheng/archive/2004/12/15/41209.aspx! M4 h9 z3 l8 U2 e
) C) r' V# I2 Q! O; z" e9 z
d.IRichEditOleCallback的使用
4 u& g: b" C( `2 L! }http://61.186.252.131/Expert/topic/905/905844.xml?temp=.8379022! d, K- O4 V" n4 Q9 G( P3 |
; T$ X) c1 w$ B2 _# T4 _+ I( S, R类似 MSN 信息发送框的制作(上)
' D1 D f# i mhttp://www.vckbase.com/document/viewdoc/?id=1087
4 x, N0 x V, I2 u7 Z内容包含:实现右键菜单,图片插入,读取/写入RTF格式字符串7 ]/ J1 @1 A4 ~$ L# P
. B# K* [7 K$ B9 h5 X! Q2 C9 s自定义 CRichEditCtrl 控件9 o9 C% N2 v! L6 k
http://www.vckbase.com/document/viewdoc/?id=328
# e* I" s1 m: d* X$ V2 W内容包含:鼠标右键消息,消息映射,字体变换
, q8 b3 R2 h+ b/ f t3 U9 S" H5 S; U7 D+ X) ~! [# i4 Z
PS.richedit控件升级到2.0后,先把字体设为楷体,输入汉字没有问题,但输入字母时,字母自动跳转为Arial字体,而1.0却没有这个文题,仍然是用楷体显示字母
9 L+ q7 o% F3 G& \8 a是一个专门的设计 Dual-font, Smart font apply, 参见 http://61.186.252.131/Expert/topic/913/913807.xml?temp=.3753778 : W! X9 }4 x) _: Z2 }8 z; \8 A
----------------------
" o& b5 |* ]! ^% t! s. _" a6 W, O比我想象中还要花时间,所以最后潦草了点,见谅 |
|