CRichEditCtrl 超链接文本颜色问题

poetao 2009-06-05 09:23:49
CRichEditCtrl设置超链接后,超链接文本的颜色都是蓝色的,有没有办法可以改变成其它颜色。我试过使用SetSelectionCharFormat(&cf) 无效。
...全文
648 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
工程师WWW 2011-07-06
  • 打赏
  • 举报
回复
看不懂
poetao 2009-06-16
  • 打赏
  • 举报
回复
这里属skyxie 兄最热情,我也就把分给他了
poetao 2009-06-16
  • 打赏
  • 举报
回复
这两天有空,终于把这个问题解决了.
决定放弃MS的EN_LINK. 采用自已设置下划线和颜色.然后再生成一个链表,自己维护链接信息.
主要代码如下:(个人比较懒,把项目中的代码照搬上来)
void CRichEditCtrlEx::InsertItemPetLink( LPCTSTR lpcszText, DWORD dwId, DWORD dwType,
DWORD dwMask, TEXTFORMAT* pTextFmt)
{
BOOL bReadOnly = (GetStyle() & ES_READONLY);
SetReadOnly(FALSE);

CHARFORMAT2 Oldcf2;
memset(&Oldcf2, 0, sizeof(CHARFORMAT2) );
Oldcf2.cbSize = sizeof(CHARFORMAT2);
SendMessage(EM_GETCHARFORMAT, (WPARAM)TRUE, (LPARAM)(&Oldcf2));

SetSel(-1, -1);

CHARFORMAT2 cf2;
memset( &cf2, 0, sizeof(CHARFORMAT2) );

memcpy( &cf2, &m_cfSelChar, sizeof(CHARFORMAT) );

cf2.cbSize = sizeof(CHARFORMAT2);
cf2.dwMask |= CFM_UNDERLINE|CFM_COLOR;
cf2.dwEffects |= CFE_UNDERLINE;
cf2.crBackColor = RGB(210,240,255);
cf2.crTextColor = 0xfc06ff;
if (pTextFmt)
{
cf2.crTextColor = pTextFmt->crTextColor;
}

CHARRANGE range;
GetSel(range);

ReplaceSel(lpcszText);
int nLen = _tcslen(lpcszText);

//在RichEdit中的位置是按多字节字符处理的包括回车符“\r\n”
CString cstrTmp = lpcszText;
cstrTmp.Replace(_T("\r\n"), _T("\n"));
int mLen = cstrTmp.GetLength();
int rnLen = nLen - mLen;

range.cpMax += _tcslen(lpcszText) - rnLen;

if( __isascii(lpcszText[nLen-1]))// && isalnum(lpcszText[nLen-1]) )
{
ReplaceSel(_T(" "));
range.cpMax += 1;
}

SetSel(range);
SendMessage(EM_SETCHARFORMAT, (WPARAM)(SCF_SELECTION), (LPARAM)(&cf2));

CItemPetLinkObj* pItemPetInfo = new CItemPetLinkObj();
if( pItemPetInfo )
{
CPoint ptStart = this->GetCharPos(range.cpMin);
CPoint ptEnd = this->GetCharPos(range.cpMax);

pItemPetInfo->dwColor = cf2.crTextColor;
pItemPetInfo->dwID = dwId;
pItemPetInfo->dwType = dwType;
pItemPetInfo->strName = lpcszText;
pItemPetInfo->range = range;

m_listItemPetLink.push_back(pItemPetInfo);
}

SetSel(-1, -1);
Oldcf2.dwMask = cf2.dwMask;
SendMessage(EM_SETCHARFORMAT, (WPARAM)(SCF_SELECTION), (LPARAM)(&Oldcf2));

SetReadOnly(bReadOnly);
}

void CRichEditCtrlEx::OnMouseMove(UINT nFlags, CPoint point)
{
CItemPetList::const_iterator iter = m_listItemPetLink.begin();
for (; iter != m_listItemPetLink.end(); ++iter)
{
if (NULL != m_pIRichCallback && NULL != (*iter))
{
CPoint ptStart = this->GetCharPos((*iter)->range.cpMin);
CPoint ptEnd = this->GetCharPos((*iter)->range.cpMax);
CRect rcClient;
this->GetRect(&rcClient);

CRect rcText;
if (ptEnd.y > ptStart.y) // 分了两行显示时
{
rcText = CRect(ptStart.x, ptStart.y, rcClient.right, ptStart.y+16);
if (rcText.PtInRect(point))
{
g_objChatInfoMgr.SetCursor(CURSOR_TYPE_CLICK);
break;
}

rcText = CRect(rcClient.left, ptEnd.y, ptEnd.x, ptEnd.y+16);
if (rcText.PtInRect(point))
{
g_objChatInfoMgr.SetCursor(CURSOR_TYPE_CLICK);
break;
}
}
else // 单行
{
rcText = CRect(ptStart.x, ptStart.y, ptEnd.x, ptStart.y+16);
if (rcText.PtInRect(point))
{
g_objChatInfoMgr.SetCursor(CURSOR_TYPE_CLICK);
break;
}
}
}
}

CRichEditCtrl::OnMouseMove(nFlags, point);
}

void CRichEditCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
{
CRichEditCtrl::SetFocus();
CRichEditCtrl::OnLButtonDown(nFlags, point);

CItemPetList::const_iterator iter = m_listItemPetLink.begin();
for (; iter != m_listItemPetLink.end(); ++iter)
{
if (NULL != m_pIRichCallback && NULL != (*iter))
{
CPoint ptStart = this->GetCharPos((*iter)->range.cpMin);
CPoint ptEnd = this->GetCharPos((*iter)->range.cpMax);
CRect rcClient;
this->GetRect(&rcClient);

CRect rcText;
if (ptEnd.y > ptStart.y) // 分了两行显示时
{
rcText = CRect(ptStart.x, ptStart.y, rcClient.right, ptStart.y+16);
if (rcText.PtInRect(point))
{
m_pIRichCallback->OnLinkClick( this->m_hWnd, (*iter)->dwID, 0, (*iter)->dwType, (*iter)->strName.c_str());
break;
}

rcText = CRect(rcClient.left, ptEnd.y, ptEnd.x, ptEnd.y+16);
if (rcText.PtInRect(point))
{
m_pIRichCallback->OnLinkClick( this->m_hWnd, (*iter)->dwID, 0, (*iter)->dwType, (*iter)->strName.c_str());
break;
}
}

rcText = CRect(ptStart.x, ptStart.y, ptEnd.x, ptStart.y+16);
if (rcText.PtInRect(point))
{
m_pIRichCallback->OnLinkClick( this->m_hWnd, (*iter)->dwID, 0, (*iter)->dwType, (*iter)->strName.c_str());
break;
}
}
}
}

其中有一些代码是和我的项目相关,但与本帖问题无关的,相信大家能看出来.(主要是我比较懒)
na_he 2009-06-09
  • 打赏
  • 举报
回复
隐藏在正常的文字后面不晓的可以吗
poetao 2009-06-09
  • 打赏
  • 举报
回复
或者有没有另外一种变通的办法,插入普通文本,这样可以自己设置下划线和颜色.但难点是要自己捕捉鼠标的点击事件.不知道怎样准确的捕捉到点击事件.
poetao 2009-06-09
  • 打赏
  • 举报
回复
处理EN_LINK没有用.
这个消息是处理已经是链接的文本相关通知事件,比如单击等.在这个层面上,我没有办法采取自绘文本之类的动作,要改变颜色,还是靠SendMessage(EM_SETCHARFORMAT, (WPARAM)(SCF_SELECTION), (LPARAM)(&cf2)); 这和在插入文本当初采用的动作是一样的.
如果要是能在插入文本后,象其它控件一样开放一个OnDraw的自绘的接口,或许还有可能.不过好像没有这样的接口.
poetao 2009-06-06
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 skyxie 的回复:]
引用 4 楼 poetao 的回复:
用CHATFORMAT2版,

cf2.dwMask = CFM_COLOR;
cf2.crTextColor = RGB(255, 0, 0);
int nResult =  SendMessage(EM_SETCHARFORMAT, (WPARAM)(SCF_SELECTION), (LPARAM)(&cf2));

执行完后,nResult == 1;看上去挺正常,就是颜色不变,还是蓝色


问题不在于版本,你没有用cf2版本的成员

你SendMessage的时候link的部分是选中的吗?
倒是 SCF_SELECTION 改成 SCF_ALL,试试看看是不是所有的(包…
[/Quote]

我保证是有选中的。
改成SCF_ALL, 其它部分都是红色的了,LINK部分依然是蓝色。
你有把LINK改成其它颜色成功的Demon吗?有发我一份wutao1017@163.com
skyxie 2009-06-06
  • 打赏
  • 举报
回复
下午尝试写了一个demo

试了普通的方法和使用COM接口的方法。都失败了。


#define TEST_TEXT _T("To test link color.")
HGLOBAL hClip;
if(OpenClipboard())
{
::EmptyClipboard();
hClip = GlobalAlloc(GMEM_MOVEABLE, _tcslen(TEST_TEXT) + 1 );
TCHAR *buff;
buff = (TCHAR*)GlobalLock(hClip);
_tcscpy(buff, TEST_TEXT);
::GlobalUnlock(hClip);
::SetClipboardData(CF_TEXT, hClip);
::CloseClipboard();
}

m_richedit.Paste();

CHARFORMAT2 cf2;

m_richedit.SetSel(8, 12); //将"link"这个词选中

// 设为link
ZeroMemory(&cf2, sizeof(CHARFORMAT2));
cf2.cbSize = sizeof(CHARFORMAT2);
cf2.dwMask = CFM_LINK;
cf2.dwEffects |= CFE_LINK;
::SendMessage(GetDlgItem(IDC_RICHEDIT)->GetSafeHwnd(), EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);

#if 0
// 修改link的字体颜色为红色,不起作用
ZeroMemory(&cf2, sizeof(CHARFORMAT2));
cf2.cbSize = sizeof(CHARFORMAT2);
cf2.dwMask = CFM_COLOR;
cf2.dwEffects = CFE_BOLD;
cf2.crTextColor = RGB(255, 0, 0);
m_richedit.SetWordCharFormat(cf2);
#endif

HRESULT hr;
CComPtr<IRichEditOle> spREOle;
::SendMessage( GetDlgItem(IDC_RICHEDIT)->GetSafeHwnd(),
EM_GETOLEINTERFACE,
0, /*not used; must be zero.*/
(LPARAM)&spREOle);

CComQIPtr<ITextDocument> spTextDoc = spREOle;
CComPtr<ITextSelection> spSelection;
hr = spTextDoc->GetSelection(&spSelection);
#if 0
//返回S_FALSE,表明link部分并不是一个embeded对象
CComPtr<IUnknown> spUnk;
hr = spSelection->GetEmbeddedObject(&spUnk);
#endif
CComPtr<ITextFont> spTextFont;
hr = spSelection->GetFont(&spTextFont);
hr = spTextFont->SetProtected(tomFalse);
//hr = spTextFont->GetForeColor(&color); //能取到 blue
//hr = spTextFont->SetBackColor(RGB(255,0,0)); //能把背景设为red
// hr = spTextFont->SetItalic(tomTrue); //能设置为斜体
//hr = spTextFont->SetUnderline(tomNone); // hr 为S_OK,但是link下面还是有下划线
hr = spTextFont->SetForeColor(RGB(255,0,0)); // hr 为S_OK
long color;
hr = spTextFont->GetForeColor(&color); // 但是link的颜色没有变

//结论, 对标准的RichEdit,设置为CFE_LINK之后,
//凡是和超链接相关的外观(字体颜色,下划线)都修改不了


要改link文字的颜色,
估计只有自己处理EN_LINK这个通知消息

A rich edit control sends EN_LINK messages when it receives various messages, for example, when the user clicks the mouse or when the mouse pointer is over text that has the CFE_LINK effect.

The parent window of the control receives this notification message through a WM_NOTIFY message.


If you return zero, the control proceeds with its normal handling of the message.

If you return a nonzero value, the control does not handle the message.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To receive EN_LINK notifications, specify the ENM_LINK flag in the mask sent with the EM_SETEVENTMASK message.



楼主自己去试试这种方法吧。

有结果了如果能贴出来share一下更好。



skyxie 2009-06-06
  • 打赏
  • 举报
回复
目前没有,下午写一个demo试试看能不能解决。
skyxie 2009-06-05
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 poetao 的回复:]
用CHATFORMAT2版,

cf2.dwMask = CFM_COLOR;
cf2.crTextColor = RGB(255, 0, 0);
int nResult = SendMessage(EM_SETCHARFORMAT, (WPARAM)(SCF_SELECTION), (LPARAM)(&cf2));

执行完后,nResult == 1;看上去挺正常,就是颜色不变,还是蓝色
[/Quote]

问题不在于版本,你没有用cf2版本的成员

你SendMessage的时候link的部分是选中的吗?
倒是 SCF_SELECTION 改成 SCF_ALL,试试看看是不是所有的(包括link部分)都变成红色了?

poetao 2009-06-05
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 RichyMong 的回复:]
C/C++ code

FINDTEXTEXW findText;
findText.chrg.cpMin = nStartPos; //自己定义查找的起始点点
findText.chrg.cpMax = -1; //结束点
findText.lpstrText = _T("要设为link的文字");
m_dlgRichEditRead.m_reRead.SetSel(findText.chrgText);
if( -1 < m_dlgRichEditRead.m_reRead.FindText(FR_DOWN, (_findtextexa *)&findText))
{
SetSel(findText.chrgText);
CHARFORMAT2 cf2;
ZeroMemory(&cf2, si…
[/Quote]

你这只是设置了一下链接,并没有设置其颜色. 我是想把设置成链接的文本可以自定义为其它的颜色
Fireway2008 2009-06-05
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 poetao 的回复:]
用CHATFORMAT2版,

cf2.dwMask = CFM_COLOR;
cf2.crTextColor = RGB(255, 0, 0);
int nResult = SendMessage(EM_SETCHARFORMAT, (WPARAM)(SCF_SELECTION), (LPARAM)(&cf2));

执行完后,nResult == 1;看上去挺正常,就是颜色不变,还是蓝色
[/Quote]


感觉5楼的代码是关键,修改一下设置参数吧
RichyMong 2009-06-05
  • 打赏
  • 举报
回复


FINDTEXTEXW findText;
findText.chrg.cpMin = nStartPos; //自己定义查找的起始点点
findText.chrg.cpMax = -1; //结束点
findText.lpstrText = _T("要设为link的文字");
m_dlgRichEditRead.m_reRead.SetSel(findText.chrgText);
if( -1 < m_dlgRichEditRead.m_reRead.FindText(FR_DOWN, (_findtextexa *)&findText))
{
SetSel(findText.chrgText);
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);
SetEventMask(ENM_LINK);
//********//
HideSelection(TRUE, FALSE);
}



我就是这样用的没有问题啊
poetao 2009-06-05
  • 打赏
  • 举报
回复
用CHATFORMAT2版,

cf2.dwMask = CFM_COLOR;
cf2.crTextColor = RGB(255, 0, 0);
int nResult = SendMessage(EM_SETCHARFORMAT, (WPARAM)(SCF_SELECTION), (LPARAM)(&cf2));

执行完后,nResult == 1;看上去挺正常,就是颜色不变,还是蓝色
skyxie 2009-06-05
  • 打赏
  • 举报
回复
1. 你是用的CHARFORMAT2版本的那个函数还是CHARFORMAT版本的那个?

2. SetSelectionCharFormat有没有返回TRUE?
poetao 2009-06-05
  • 打赏
  • 举报
回复
在CRichEditCtrl 插入一个超链接的文本,也就是设置了CFM_LINK格式.

15,976

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧