//需要用枚举的办法来获得指定OLE的显示位置,不知道有没有其它更好的办法。 BOOL CImageOle::GetOleRect( LPRECT lpRect ) { IRichEditOle *pRichEditOle=NULL; LRESULT lRes=m_pRichedit->DuiSendMessage(EM_GETOLEINTERFACE,0,(LPARAM)&pRichEditOle); if(!pRichEditOle) return FALSE; BOOL bRet=FALSE; int nObjCount = pRichEditOle->GetObjectCount(); int i = 0; for (i = 0;i < nObjCount;i++) { REOBJECT reo; ZeroMemory(&reo, sizeof(REOBJECT)); reo.cbStruct = sizeof(REOBJECT); HRESULT hr = pRichEditOle->GetObject(i, &reo, REO_GETOBJ_POLEOBJ); if (hr != S_OK) continue; reo.poleobj->Release(); if (reo.poleobj == (IOleObject *)this) { ITextDocument *pTextDocument = NULL; ITextRange *pTextRange = NULL; pRichEditOle->QueryInterface(IID_ITextDocument, (void **)&pTextDocument); if (!pTextDocument) break; long nLeft = 0; long nBottom = 0; pTextDocument->Range(reo.cp, reo.cp, &pTextRange); if (reo.dwFlags & REO_BELOWBASELINE) hr = pTextRange->GetPoint(TA_BOTTOM|TA_LEFT, &nLeft, &nBottom); else hr = pTextRange->GetPoint(TA_BASELINE|TA_LEFT, &nLeft, &nBottom); pTextDocument->Release(); pTextRange->Release(); CRect rcRichedit; GetWindowRect(m_pRichedit->GetContainer()->GetHostHwnd(),&rcRichedit); CSize szOle=m_pSkin->GetSkinSize(); lpRect->left = nLeft - rcRichedit.left; lpRect->bottom = nBottom - rcRichedit.top; lpRect->right = lpRect->left + szOle.cx ; lpRect->top = lpRect->bottom - szOle.cy; bRet=TRUE; break; } } pRichEditOle->Release(); return bRet; }
BOOL RichEditPara::GetLineRect(int nLineNo, CRect& rcLine) { rcLine.SetRectEmpty(); int ncpStart; int nLength; m_pObjectHost->SendMessage(EM_LINEINDEX, nLineNo, 0, (LRESULT*)&ncpStart); m_pObjectHost->SendMessage(EM_LINELENGTH, ncpStart, 0, (LRESULT*)&nLength); SComPtr<ITextRange> spRangeLine; ITextDocument * pdoc = m_pObjectHost->GetTextDoc(); pdoc->Range(ncpStart, ncpStart + nLength, &spRangeLine); if (!spRangeLine) { return FALSE; } CHARRANGE chr = {ncpStart, ncpStart + nLength}; // http://technet.microsoft.com/zh-cn/hh768766(v=vs.90) 新类型定义 #define _tomClientCoord 256 // 默认获取到的是屏幕坐标, Use client coordinates instead of screen coordinates. #define _tomAllowOffClient 512 // Allow points outside of the client area. long lTypeTopLeft = _tomAllowOffClient|_tomClientCoord|tomStart|TA_TOP|TA_LEFT; long lTypeRightBottom = _tomAllowOffClient|_tomClientCoord|tomEnd|TA_BOTTOM|TA_RIGHT; POINT ptEnd, ptStart; spRangeLine->GetPoint(lTypeTopLeft, &ptStart.x, &ptStart.y); spRangeLine->GetPoint(lTypeRightBottom, &ptEnd.x, &ptEnd.y); rcLine.SetRect(ptStart, ptEnd); if (rcLine.Width() == 0) { rcLine.right += 1; } return TRUE; }
static void SetPosition(HWND hwnd) { IRichEditOle* RichEditOle; if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) return; ITextDocument* TextDocument; if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) { RichEditOle->Release(); return; } // retrieve text range ITextRange* TextRange; if (TextDocument->Range(0, 0, &TextRange) != S_OK) { TextDocument->Release(); RichEditOle->Release(); return; } TextDocument->Release(); int objectCount = RichEditOle->GetObjectCount(); for (int i = objectCount - 1; i >= 0; i--) { REOBJECT reObj = {0}; reObj.cbStruct = sizeof(REOBJECT); HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ); if (FAILED(hr)) continue; ISmileyBase *igsc = NULL; if (reObj.clsid == CLSID_NULL) reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc); reObj.poleobj->Release(); if (igsc == NULL) continue; TextRange->SetRange(reObj.cp, reObj.cp); BOOL res; POINT pt; RECT rect; hr = TextRange->GetPoint(tomStart | TA_BOTTOM | TA_LEFT, &pt.x, &pt.y); if (hr == S_OK) { res = ScreenToClient(hwnd, &pt); rect.bottom = pt.y; rect.left = pt.x; } else rect.bottom = -1; hr = TextRange->GetPoint(tomStart | TA_TOP | TA_LEFT, &pt.x, &pt.y); if (hr == S_OK) { res = ScreenToClient(hwnd, &pt); rect.top = pt.y; rect.left = pt.x; } else rect.top = -1; igsc->SetPosition(hwnd, &rect); igsc->Release(); } TextRange->Release(); RichEditOle->Release(); }
void RichEditPara::UpdatePosition() { RichEditObj::UpdatePosition(); if (m_bDisableLayout) { // 如果不需要布局,直接返回 return; } CComPtr<ITextPara> ppara; CComPtr<ITextRange> prange; ITextDocument* pdoc = m_pObjectHost->GetTextDoc(); CHARRANGE chr = m_chrContent; if (m_bBreakAtTheEnd) { chr.cpMax += 1; } pdoc->Range(chr.cpMin, chr.cpMax, &prange); prange->GetPara(&ppara); if (!m_bInited) { m_bInited = TRUE; ppara->SetSpaceBefore(px2pt(m_rcMargin.top)); ppara->SetSpaceAfter(px2pt(m_rcMargin.bottom)); } CRect rcAdjust = m_pObjectHost->GetAdjustedRect(); CRect rcClient = m_pObjectHost->GetHostRect(); int nLeftIndents = m_alignType==ALIGN_RIGHT? m_rcMargin.right : m_rcMargin.left; int nRightIndents = m_alignType==ALIGN_RIGHT? m_rcMargin.left: m_rcMargin.right; nRightIndents += rcClient.Width() - rcAdjust.Width();// 计算真实的右边距 // 尽量不要使用模拟计算,能提高速度 if (!m_bSimulateAlign || m_alignType == ALIGN_LEFT) { m_bWrapped = IsWrapped(); if (m_bNeedUpdateLayout) { int nAlign = tomAlignLeft; if (m_alignType == ALIGN_RIGHT) nAlign = tomAlignRight; else if (m_alignType == ALIGN_CENTER) nAlign = tomAlignCenter; ppara->SetAlignment(nAlign); ppara->SetIndents(0, px2pt(nLeftIndents), px2pt(nRightIndents)); m_bNeedUpdateLayout = FALSE; } return; } /* 模拟计算右对齐 * 注意:SetIndents和CalcParagraphRect很耗时,所以尽量不使用模拟计算靠右 * * 1.先按最靠边的左右缩进设置 * 2.按照cp计算段落的rect * 3.用richedit.width() - para.widht()计算左缩进,模拟右对齐 * 4.根据计算出的左/缩进重新设置 */ // step 1 ppara->SetIndents(0, px2pt(nLeftIndents), px2pt(nRightIndents)); if ((m_bWrapped = IsWrapped())) return; // step 2 CalcParagraphRect(); // step 3 if (m_alignType == ALIGN_RIGHT) { nLeftIndents = rcClient.Width() - m_rcObj.Width() - nRightIndents - 1; // 这里不减1,段落就换行了 } else { int mid = (rcClient.Width() - m_rcObj.Width() - nRightIndents -nLeftIndents) / 2 - 1; nLeftIndents = m_rcMargin.left + mid; nRightIndents = m_rcMargin.right + mid; } // step 4 ppara->SetIndents(0, px2pt(nLeftIndents), px2pt(nRightIndents)); m_bNeedUpdateLayout = FALSE; m_bDirty = TRUE; }