Recently I have been searching The Code Project on how to show subscripts and superscripts in the device context (when using TextOut
or ExtTextOut
functions). But I could not find anything. So finally I decided to write the function myself.
My function SSTextOut
has similar functionality to ExtTextOut
. You need to specify the pointer to the device context, the pointer to bounding rectangle, the string
itself, and the justification mode.
The string
should contain special formatting codes - ^
for superscript and _
for subscript. The next symbol after ^
or _
will be shown as subscript or superscript. If you need to show ^
or _
themselves - just type them twice - ^^
or __
.
Justification can be DT_CENTER
, DT_LEFT
, or DT_RIGHT
. It affects only horizontal justification. Vertically, the text will be centered in the bounding rectangle automatically. The text outside the rectangle is clipped. The function uses the current font of the specified device context.
So, to draw the meaningless text in the image above, you need to call:
SSTextOut(pDC,"ms^2/Hz+H_2O-mc^^2__4",&rect,DT_CENTER);
The source code of SSTextOut
is shown below:
void SSTextOut(CDC* pDC, CString data , CRect* drawRect, int justification){ //Necessary initializations pDC->SaveDC(); CSize sz; CRect outRect(0,0,0,0); CFont* pFont = pDC->GetCurrentFont(); CFont* oldFont; pDC->SetTextAlign(TA_BOTTOM|TA_LEFT); LOGFONT lf; pFont->GetLogFont(&lf); CPoint sub,sup,subofs,supofs; // Calculate subscript/superscript size and offsets sub.x=lf.lfWidth/2; sup.x=lf.lfWidth/2; sub.y=lf.lfHeight/3*2; sup.y=lf.lfHeight/3*2; subofs.x=lf.lfWidth/2; supofs.x=lf.lfWidth/2; subofs.y=lf.lfHeight/6; supofs.y=lf.lfHeight/3; lf.lfWidth=sub.x; lf.lfHeight=sub.y; CFont SubFont; SubFont.CreateFontIndirect(&lf); lf.lfWidth=sup.x; lf.lfHeight=sup.y; CFont SupFont; SupFont.CreateFontIndirect(&lf); CString temp = data; TCHAR c; // Calculate the size of the text that needs to be displayed do { int x=0; CString s = ""; c=' '; bool bFind=true; // Find the first "^" or "_", indicating the sub- or superscript while (bFind) { x=data.FindOneOf("^_"); if (x==-1) { bFind=false; x=data.GetLength(); } else if (x==data.GetLength()-1) bFind=false; else if (data[x]!=data[x+1]) { bFind=false; c=data[x]; } else x++; s=s+data.Left(x); data.Delete(0,min(x+1,data.GetLength())); } sz = pDC->GetTextExtent(s); outRect.right+=sz.cx; if (outRect.Height()<sz.cy) outRect.top=outRect.bottom-sz.cy; switch (c) { case '^': oldFont = pDC->SelectObject(&SupFont); sz = pDC->GetTextExtent(data[0]); outRect.right+=sz.cx+supofs.x; data.Delete(0); pDC->SelectObject(oldFont); break; case '_': oldFont = pDC->SelectObject(&SubFont); sz = pDC->GetTextExtent(data[0]); outRect.right+=sz.cx+subofs.x; data.Delete(0); pDC->SelectObject(oldFont); break; } } while (c!=' '); // Adjust text position outRect.bottom+=2*subofs.y; outRect.top-=2*subofs.x; CPoint Origin; Origin.y = drawRect->Height()/2+outRect.Height()/2+drawRect->top; switch (justification) { case DT_CENTER: Origin.x = drawRect->Width()/2-outRect.Width()/2+drawRect->left; break; case DT_LEFT: Origin.x = drawRect->left; break; case DT_RIGHT: Origin.x = drawRect->right-outRect.Width(); } CPoint pnt = Origin; data = temp; // Draw text do { int x=0; CString s = ""; c=' '; bool bFind=true; // Find the first "^" or "_", indicating the sub- or superscript while (bFind) { x=data.FindOneOf("^_"); if (x==-1) { bFind=false; x=data.GetLength(); } else if (x==data.GetLength()-1) bFind=false; else if (data[x]!=data[x+1]) { bFind=false; c=data[x]; } else x++; s=s+data.Left(x); data.Delete(0,min(x+1,data.GetLength())); } // Draw main text pDC->ExtTextOut(pnt.x,pnt.y,ETO_CLIPPED,drawRect,s,NULL); sz = pDC->GetTextExtent(s); pnt.x+=sz.cx; // Draw subscript or superscript switch (c) { case '^': oldFont = pDC->SelectObject(&SupFont); pDC->ExtTextOut(pnt.x+supofs.x,pnt.y-supofs.y,ETO_CLIPPED,drawRect,data[0],NULL); sz = pDC->GetTextExtent(data[0]); pnt.x+=sz.cx+supofs.x; data.Delete(0); pDC->SelectObject(oldFont); break; case '_': oldFont = pDC->SelectObject(&SubFont); pDC->ExtTextOut(pnt.x+subofs.x,pnt.y+subofs.y,ETO_CLIPPED,drawRect,data[0],NULL); sz = pDC->GetTextExtent(data[0]); pnt.x+=sz.cx+supofs.x; data.Delete(0); pDC->SelectObject(oldFont); break; } } while (c!=' '); // Done, restoring the device context pDC->RestoreDC(-1);}
联系客服