Display an index using DrawText or a similar function

The question is simple. How to draw the following text in a TStringGrid cell?

enter image description here

Operating system - Windows XP (or Windows Vista or Windows 7). The preferred development environment is C ++ Builder 6, but I also agree with the C ++ Builder XE solutions from Delphi. The preferred API function is DrawText , but if there is a more efficient function, this is not a problem. The font name is Times New Roman , the font size is 11. I am currently using this method to render the contents of a cell (simplified):

 void __fastcall TForm_Main::StringGrid_DrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State) { TStringGrid *grid = (TStringGrid*)Sender; if (grid == NULL) return; // 1. BACKGROUND grid->Canvas->Brush->Color = grid->Color; grid->Canvas->FillRect(Rect); // 2. TEXT grid->Canvas->Font->Assign(grid->Font); // Times New Roman, 11pt // horizontal centering RECT RText = static_cast<RECT>(Rect); AnsiString text = grid->Cells[ACol][ARow]; if (!text.IsEmpty()) { int text_len = strlen(text.c_str()); SIZE size; memset(&size, 0, sizeof(SIZE)); GetTextExtentPoint32(grid->Canvas->Handle, text.c_str(), text_len, &size); int offset_x = (Rect.Width() - size.cx) >> 1; RText.left += offset_x; RText.right += offset_x; // rendering DrawText(grid->Canvas->Handle, text.c_str(), text_len, &RText, DT_LEFT | DT_VCENTER | DT_SINGLELINE); } } 

Some characters have an index character as a special Unicode character (for example, the code 0x2081 is assigned to the lower index), but, unfortunately, this is not the case for the capital letter U. Also, these characters are not supported by all fonts (for example, the Times New Roman font does not support the code range 0x2070 - 209F), see this Wikipedia article. I am looking for a more general solution, similar to those implemented by Microsoft Word. MS Word has no problem to capitalize the letter U as an index using the Times New Roman font.

+4
source share
2 answers

If you want some char to display as a superscript, you must prefix it with ^. Similarly, subscript characters must be prefixed with _.

 void __fastcall TForm_Main::StringGrid_DrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State) { TStringGrid *grid = (TStringGrid*)Sender; if (grid == NULL) { return; } WideString wtext = L"φ_U = 120"; if (wtext.IsEmpty()) return; // layout SIZE size; memset(&size, 0, sizeof(SIZE)); SSGetTextExtentPoint(grid->Canvas, wtext, size); int offset_x = (Rect.Width() - size.cx + 1) >> 1; // horizontal centering RECT RText = static_cast<RECT>(Rect); RText.left += offset_x; RText.right += offset_x; // rendering SetBkMode(grid->Canvas->Handle, TRANSPARENT); SSDrawText(grid->Canvas, wtext, RText, DT_LEFT); } int TForm_Main::SSGetTextExtentPoint(TCanvas *canvas, WideString text, SIZE &size) { // Source: http://www.codeproject.com/Articles/12660/Using-Subscripts-and-Superscripts-When-Showing-Tex SaveDC(canvas->Handle); SIZE sz; RECT outRect = {0, 0, 0, 0}; HFONT oldFont; LOGFONT lf; GetObject(canvas->Font->Handle, sizeof(LOGFONT), &lf); POINT sub, sup, subofs, supofs; // Calculate subscript/superscript size and offsets bool use_pixel_unit = false; if (lf.lfHeight < 0) { lf.lfHeight = MulDiv(-lf.lfHeight, 72, GetDeviceCaps(canvas->Handle, LOGPIXELSY)); use_pixel_unit = true; } 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; if (use_pixel_unit) { lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(canvas->Handle, LOGPIXELSY), 72); } HFONT SubFont; SubFont = CreateFontIndirect(&lf); lf.lfWidth = sup.x; lf.lfHeight = sup.y; HFONT SupFont; if (use_pixel_unit) { lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(canvas->Handle, LOGPIXELSY), 72); } SupFont = CreateFontIndirect(&lf); WideString temp = text; TCHAR c; // Calculate the size of the text that needs to be displayed do { int x1 = 1, x2 = 1, x = 1; WideString s = ""; c = ' '; bool bFind = true; // Find the first "^" or "_", indicating the sub- or superscript while (bFind) { x1 = text.Pos(L"^"); x2 = text.Pos(L"_"); if ((x1 == 0) && (x2 == 0)) { x = 0; } else if ((x1 > 0) && (x2 > 0)) { x = min(x1, x2); } else if (x1 > 0) { x = x1; } else { x = x2; } if (x == 0) { bFind = false; x = text.Length() + 1; } else if (x == text.Length()) { bFind = false; } else if (text[x] != text[x + 1]) { bFind = false; c = text[x]; } else { x++; } s = s + text.SubString(1, x - 1); text.Delete(1, min(x, text.Length())); } sz = canvas->TextExtent(s); outRect.right += sz.cx; if ((outRect.bottom - outRect.top) < sz.cy) { outRect.top = outRect.bottom - sz.cy; } switch (c) { case '^': oldFont = (HFONT)SelectObject(canvas->Handle, SupFont); GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz); outRect.right += sz.cx + supofs.x; text.Delete(1, 1); SelectObject(canvas->Handle, oldFont); break; case '_': oldFont = (HFONT)SelectObject(canvas->Handle, SubFont); GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz); outRect.right += sz.cx + subofs.x; text.Delete(1, 1); SelectObject(canvas->Handle, oldFont); break; } } while (c != ' '); // Adjust text position outRect.bottom += subofs.y; outRect.top -= subofs.x; size.cx = outRect.right - outRect.left; size.cy = outRect.bottom - outRect.top; DeleteObject(SubFont); DeleteObject(SupFont); // Done, restoring the device context RestoreDC(canvas->Handle, -1); return 0; } // --------------------------------------------------------------------------- int TForm_Main::SSDrawText(TCanvas *canvas, WideString text, RECT &drawRect, int justification) { // Source: http://www.codeproject.com/Articles/12660/Using-Subscripts-and-Superscripts-When-Showing-Tex SaveDC(canvas->Handle); SIZE sz; RECT outRect = {0, 0, 0, 0}; HFONT oldFont; LOGFONT lf; GetObject(canvas->Font->Handle, sizeof(LOGFONT), &lf); POINT sub, sup, subofs, supofs; bool contains_subscript = false; bool contains_superscript = false; // Calculate subscript/superscript size and offsets bool use_pixel_unit = false; if (lf.lfHeight < 0) { lf.lfHeight = MulDiv(-lf.lfHeight, 72, GetDeviceCaps(canvas->Handle, LOGPIXELSY)); use_pixel_unit = true; } sub.x = (lf.lfWidth + 1) >> 1; sup.x = (lf.lfWidth + 1) >> 1; sub.y = (lf.lfHeight << 1) / 3; sup.y = (lf.lfHeight << 1) / 3; if (lf.lfHeight == 10) { sub.y++; // make subscript a little larger } subofs.x = (lf.lfWidth + 1) >> 1; supofs.x = (lf.lfWidth + 1) >> 1; subofs.y = (lf.lfHeight + 3) / 6; supofs.y = (lf.lfHeight) / 3; long sub_shift_down = lf.lfHeight - sub.y; lf.lfWidth = sub.x; lf.lfHeight = sub.y; if (use_pixel_unit) { lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(canvas->Handle, LOGPIXELSY), 72); } HFONT SubFont; SubFont = CreateFontIndirect(&lf); lf.lfWidth = sup.x; lf.lfHeight = sup.y; if (use_pixel_unit) { lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(canvas->Handle, LOGPIXELSY), 72); } HFONT SupFont; SupFont = CreateFontIndirect(&lf); WideString temp = text; TCHAR c; // Calculate the size of the text that needs to be displayed do { int x1 = 1, x2 = 1, x = 1; WideString s = ""; c = ' '; bool bFind = true; // Find the first "^" or "_", indicating the sub- or superscript while (bFind) { x1 = text.Pos(L"^"); x2 = text.Pos(L"_"); if ((x1 == 0) && (x2 == 0)) { x = 0; } else if ((x1 > 0) && (x2 > 0)) { x = min(x1, x2); } else if (x1 > 0) { x = x1; } else { x = x2; } if (x == 0) { bFind = false; x = text.Length() + 1; } else if (x == text.Length()) { bFind = false; } else if (text[x] != text[x + 1]) { bFind = false; c = text[x]; } else { x++; } s = s + text.SubString(1, x - 1); text.Delete(1, min(x, text.Length())); } sz = canvas->TextExtent(s); outRect.right += sz.cx; if ((outRect.bottom - outRect.top) < sz.cy) { outRect.top = outRect.bottom - sz.cy; } switch (c) { case '^': oldFont = (HFONT)SelectObject(canvas->Handle, SupFont); GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz); outRect.right += sz.cx + supofs.x; text.Delete(1, 1); SelectObject(canvas->Handle, oldFont); contains_superscript = true; break; case '_': oldFont = (HFONT)SelectObject(canvas->Handle, SubFont); GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz); outRect.right += sz.cx + subofs.x; text.Delete(1, 1); SelectObject(canvas->Handle, oldFont); contains_subscript = true; break; } } while (c != ' '); // Adjust text position if (contains_subscript) { outRect.bottom += subofs.y; } if (contains_superscript) { outRect.top -= supofs.y; } POINT Origin; Origin.y = drawRect.top + (((drawRect.bottom - drawRect.top) - (outRect.bottom - outRect.top) + 1) >> 1); switch (justification) { case DT_CENTER: Origin.x = (drawRect.right - drawRect.left) / 2 - (outRect.right - outRect.left) / 2 + drawRect.left; break; case DT_LEFT: Origin.x = drawRect.left; break; case DT_RIGHT: Origin.x = drawRect.right - (outRect.right - outRect.left); } POINT pnt = Origin; text = temp; // Draw text do { int x1 = 1, x2 = 1, x = 1; WideString s = ""; c = ' '; bool bFind = true; // Find the first "^" or "_", indicating the sub- or superscript while (bFind) { x = text.Pos(L"^_"); x1 = text.Pos(L"^"); x2 = text.Pos(L"_"); if ((x1 == 0) && (x2 == 0)) { x = 0; } else if ((x1 > 0) && (x2 > 0)) { x = min(x1, x2); } else if (x1 > 0) { x = x1; } else { x = x2; } if (x == 0) { bFind = false; x = text.Length() + 1; } else if (x == text.Length()) { bFind = false; } else if (text[x] != text[x + 1]) { bFind = false; c = text[x]; } else { x++; } s = s + text.SubString(1, x - 1); text.Delete(1, min(x, text.Length())); } // Draw main text ExtTextOutW(canvas->Handle, pnt.x, pnt.y, 0, &drawRect, s.c_bstr(), s.Length(), NULL); GetTextExtentPoint32W(canvas->Handle, s.c_bstr(), s.Length(), &sz); pnt.x += sz.cx; // Draw subscript or superscript switch (c) { case '^': oldFont = (HFONT)SelectObject(canvas->Handle, SupFont); ExtTextOutW(canvas->Handle, pnt.x + supofs.x, pnt.y - supofs.y, 0, &drawRect, text.c_bstr(), 1, NULL); GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz); pnt.x += sz.cx + supofs.x; text.Delete(1, 1); SelectObject(canvas->Handle, oldFont); break; case '_': oldFont = (HFONT)SelectObject(canvas->Handle, SubFont); ExtTextOutW(canvas->Handle, pnt.x + subofs.x, pnt.y + subofs.y + sub_shift_down, 0, &drawRect, text.c_bstr(), 1, NULL); GetTextExtentPoint32W(canvas->Handle, text.c_bstr(), 1, &sz); pnt.x += sz.cx + subofs.x; text.Delete(1, 1); SelectObject(canvas->Handle, oldFont); break; } } while (c != ' '); DeleteObject(SubFont); DeleteObject(SupFont); // Done, restoring the device context RestoreDC(canvas->Handle, -1); return 0; } 
0
source

'function SSTextLeft (ACanvas: TCanvas; ARect: TRect; const S: string): integer;

 var i, h, h3: integer; sup, sub: boolean; begin with ACanvas, ARect do begin h:= textHeight('H'); h3:= h div 3; brush.Style:= bsClear; moveTo(Left +1, Top +1); i:= 1; while i < Length(s) +1 do begin if s[i] = '^' then begin Inc(i); font.Height:= MulDiv(font.Height, 8, 10); textOut(penPos.X, penPos.Y -h3, s[i]); moveTo(penPos.X +1, penPos.Y +h3); font.Height:= h; Inc(i); end else if s[i] = '_' then begin Inc(i); font.Height:= MulDiv(font.Height, 8, 10); textOut(penPos.X, penPos.Y +h3, s[i]); moveTo(penPos.X +1, penPos.Y -h3); font.Height:= h; Inc(i); end else begin textOut(penPos.X, penPos.Y, s[i]); Inc(i); moveTo(penPos.X +1, penPos.Y); end; end;// while end; sup:= Pos('^', S) > 0; sub:= Pos('_', S) > 0; if sup and sub then result:= MulDiv(h, 5, 3) else if sup or sub then result:= h +h3 else result:= h; end;// SSTextLeft 

"

0
source

Source: https://habr.com/ru/post/1397422/


All Articles