Using TWPPaintEngine to paint RTF text into a TVirtualStringTree cell
Combined with what? It seems that the values in PaintEngine.Memo._PaintRectHeight respectively PaintEngine.Memo._PaintBottomPos are twips? Or what are they? What is the difference between _PaintRectHeight and _PaintBottomPos?
When you are dealing with normal (non-RTF) multiline text in a VST (TVirtualStringTree) you are supposed to use the Winapi.Windows.DrawText method with DT_CALCRECT or DT_WORDBREAK flags in the OnMeasureItem event. The resulting height of the text is passed to the lpRect parameter of the Winapi.Windows.DrawText method: NodeHeight := lpRect.Height.
This is how I attempt to measure the height of the text with the TWPPaintEngine class:
text := '...';
w := columnWidth; // 430 px
rtfData := TWPRTFDataCollection.Create( TWPRTFDataBlock );
pe := TWPPaintEngine.Create( Self );
bmp := TBitmap.Create;
try
rtfData.MakeRTFProps;
rtfData.Get( wpIsBody, wpraOnAllPages ).RtfText.AsString := text;
pe.RTFData := rtfData;
pe.RTFData.Header.LeftMargin := 0;
pe.RTFData.Header.RightMargin := 0;
pe.RTFData.Header.PageWidth := Round( w / Screen.PixelsPerInch * 1440 );
pe.RTFData.Header.PageHeight := MaxInt; // I don't know the required height yet - The text needs to fit in
pe.ReformatAll( TRUE );
bmp.PixelFormat := pf32Bit;
bmp.SetSize( w, 1 ); // I don't know the height yet
pe.Draw( bmp.Canvas,
0, 0, MaxInt,
Screen.PixelsPerInch, Screen.PixelsPerInch,
0
);
// What is the correct value to use here to determine the NodeHeight in pixels?
// ... pe.Memo._PaintBottomPos?
// ... pe.Memo._PaintRectHeight?
// ... Something else?
// Using Round( pe.Memo._PaintBottomPos * 0.0666666667 ) at the moment, assuming _PaintBottomPos is in twips.
NodeHeight := ???;
finally
bmp.Free;
pe.RTFData := nil;
pe.Free;
rtfData.Free;
end;
This seems to work perfectly well for some text, while other text is cut off:
You can use the resolution values from Memo
property CurrentXPixelsPerInch: Integer
property CurrentYPixelsPerInch: Integer
Thanks. This seems to work well. 👍🏻
In the TVirtualStringTree you need to calculate a node's height in the OnMeasureItem event. Do you have a suggestion on how to properly get the height of the rendered text?
I see there is PaintEngine.Memo._PaintRectHeight and PaintEngine.Memo._PaintBottomPos - Both seem to contain a value I can work with. For now I use height := PaintEngine.Memo._PaintBottomPos div 10 and it seems to get the job done in most cases.
Is there an other / better way?
I would solve this by buffered paint on a TBitmap.
Create a bitmap of the size of drawing area and paint on it. This can also be usewd for caching the drawing.
I'm using TWPPaintEngine to paint RTF text into a TVirtualStringTree cell. This works in general but I have a problem.
Sometimes, when the cell (or the drawing area) is small, the drawing result seems to be messed up in terms of line breaks or spacing between the lines.
When I expand the window just a few more pixels the text suddenly is drawn correctly:
Unfortunately this doesn't work for all texts:
In this case it doesn't seem to matter how wide the window is, the text is never drawn correctly:
What is the problem here and how can I fix that?
This is how I draw the text:
paint3.RTFData := data^.RTFData;
paint3.RTFData.Header.LeftMargin := 0;
paint3.RTFData.Header.RightMargin := 0;
paint3.RTFData.Header.PageWidth := Round( drawRect.Width / Screen.PixelsPerInch * 1440 );
paint3.RTFData.Header.PageHeight := Round( drawRect.Height / Screen.PixelsPerInch * 1440 );
paint3.Draw( TargetCanvas,
drawRect.Left, drawRect.Top, drawRect.Height,
Screen.PixelsPerInch, Screen.PixelsPerInch,
0
);
These are the RTF texts:
Example 1
{\rtf1\ansi\deff0\uc1\ansicpg1252\deftab720{\fonttbl{\f0\fnil\fcharset1 Arial;}{\f1\fnil\fcharset1 Tahoma;}{\f2\fnil\fcharset2 Wingdings;}{\f3\fnil\fcharset2 Symbol;}{\f4\fnil\fcharset4 Segoe UI Emoji;}}{\colortbl\red0\green0\blue0;\red255\green0\blue0;\red0\green128\blue0;\red0\green0\blue255;\red255\green255\blue0;\red255\green0\blue255;\red128\green0\blue128;\red128\green0\blue0;\red0\green255\blue0;\red0\green255\blue255;\red0\green128\blue128;\red0\green0\blue128;\red255\green255\blue255;\red192\green192\blue192;\red128\green128\blue128;\red0\green0\blue0;\red192\green255\blue192;}\wpprheadfoot1\paperw12240\paperh15840\margl1880\margr1880\margt1440\margb1440\headery720\footery720\ftnbj\sftnbj\sftnrstcont\nocolbal\sftnnar\saftnnar\fet0\endnhere\sectdefaultcl{\*\generator WPTools_9.4-PRM;}{\plain\f1\fs20 Innenputz 2lagig Leibung B 24 cm UP Kalkzement-Putzm. D 20mm OP Kalkzement-Putzm. gefilzt\line\line 2-lagiges Innenputzsystem DIN 18550-2 auf Leibung,\line\f1\cb16 Breite Leibung '24'\f1\cb0 cm, Putzgrund Mauerwerk, Unterputz DIN EN 998-1 aus Kalkzement-Putzm\'F6rtel, Druckfestigkeitsklasse CS II (1,5 bis 5 N/mm2), Dicke Unterputz 20 mm, Oberputz aus Kalkzement-Putzm\'F6rtel, Putzoberfl\'E4che Qualit\'E4tsstufe 2 (Q2), gefilzt, \'FCbliche Beanspruchung, Arbeitsh\'F6he der zu bearbeitenden oder zu bekleidenden Fl\'E4che bis 3,5 m \'FCber der Standfl\'E4che des hierf\'FCr erforderlichen Ger\'FCstes, Ausf\'FChrung im Erdgeschoss.\par
}}
Example 2
{\rtf1\ansi\deff0\uc1\ansicpg1252\deftab720{\fonttbl{\f0\fnil\fcharset1 Arial;}{\f1\fnil\fcharset1 Tahoma;}{\f2\fnil\fcharset2 Wingdings;}{\f3\fnil\fcharset2 Symbol;}{\f4\fnil\fcharset4 Segoe UI Emoji;}}{\colortbl\red0\green0\blue0;\red255\green0\blue0;\red0\green128\blue0;\red0\green0\blue255;\red255\green255\blue0;\red255\green0\blue255;\red128\green0\blue128;\red128\green0\blue0;\red0\green255\blue0;\red0\green255\blue255;\red0\green128\blue128;\red0\green0\blue128;\red255\green255\blue255;\red192\green192\blue192;\red128\green128\blue128;\red0\green0\blue0;}\wpprheadfoot1\paperw12240\paperh15840\margl1880\margr1880\margt1440\margb1440\headery720\footery720\ftnbj\sftnbj\sftnrstcont\nocolbal\sftnnar\saftnnar\fet0\endnhere\sectdefaultcl{\*\generator WPTools_9.4-PRM;}{\plain\f1\fs20 Anputzleiste\line\line Anputzleiste als Anschluss bei Fenster-, T\'FCr- und \line sonstigen Bauteilen liefern und anbringen\line\line Ausbilden einer wind- und schlagregendichten, bewegungsf\'E4higen Systemanschlussfuge mit Anputzleiste, bestehend aus:\line - Kunststoffleiste, selbstklebend\line - integriertem, komprimiertem\line Fugendichtband\line - Schutzfolienstreifen\line (Putzanschlag mit Kellenschnittvorgabe).\line Einbau nach Vorgaben des Herstellers.\line\line Aktivieren des integrierten Fugendichtbandes nach Fertigstellung der Putzarbeiten durch seitliches Herausziehen des Schutzfolienstreifens.\line\line\f1\cb8 Hersteller/Typ Baukom Apu mini 6 mm\f1\cb0 \line vom Bieter einzutragen.\par
}}