WPCubed Product Support

Using TWPPaintEngine to paint RTF text into a TVirtualStringTree cell

wpsupport

That is a very special question and you can ask me by e-mail, too.

#8 ♥ 0
7.4k Views 5 links 2 users 2 ♥ read 5 min

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:

🖼 VXTNQbv.png (i.imgur.com)

#6 ♥ 0
wpsupport

You can use the resolution values from Memo
property CurrentXPixelsPerInch: Integer
property CurrentYPixelsPerInch: Integer

#5 ♥ 1

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?

#4 ♥ 0
wpsupport

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.

#3 ♥ 1

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.

🖼 mlrIwMO.png (i.imgur.com)

When I expand the window just a few more pixels the text suddenly is drawn correctly:

🖼 2wncAu7.png (i.imgur.com)

Unfortunately this doesn't work for all texts:

🖼 9P0D8Qs.png (i.imgur.com)

In this case it doesn't seem to matter how wide the window is, the text is never drawn correctly:

🖼 umn9MlU.png (i.imgur.com)

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
}}
#1 ♥ 0