4

I'm outputting text from a delphi TRichedit control to a printer. There is a background image, so I'm using the EM_FORMATRANGE with this logic ...

myrichedit.Perform(EM_FORMATRANGE, 1, Longint(@Range));

... and that works fine except that when the text is rendered it always has a white background regardless of the color of the richedit. Any idea why?

EDIT: From comment posted:

Range is a RANGEFORMAT, and is assigned values like this:

Range.hdc := aCanvas.Handle; 
Range.hdcTarget := aCanvas.Handle; 
LogX := GetDeviceCaps(Range.hdc, LOGPIXELSX); 
LogY := GetDeviceCaps(Range.hdc, LOGPIXELSY); 
Range.rc.Left := x * 1440 div LogX; 
Range.rc.Right := (x+re.ClientWidth) * 1440 div LogX; // (1440=twips/inch)
Range.rc.Top := y * 1440 div LogY; 
Range.rc.Bottom := 5000 * 1440 div LogY; // Some bigish number 
Range.rcPage := Range.rc; 
Range.chrg.cpMin := 0; 
Range.chrg.cpMax := -1;
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
Terry
  • 274
  • 1
  • 4
  • 16
  • What is `Range`? According to [MSDN](http://msdn.microsoft.com/en-us/library/windows/desktop/bb788020%28v=vs.85%29.aspx) it's a `FORMATRANGE`, but you've given us no info about what you're actually passing as that parameter. It's hard to tell what might be wrong if you're not telling us what you're doing. :) – Ken White Feb 28 '12 at 23:49
  • @KenWhite Yes it's a FORMATRANGE and it all works as you'd expect except that the background color of the RichEdit doesn't come through. The range only specifies handles and location info in any case. One possible solution is to use a 0 as the second param so that it only measures, then draw a filled rectangle of that size, and then draw the text transparently on top, but that seems like cracking a nut with a sledgehammer... – Terry Feb 29 '12 at 01:30
  • Again, you've given us **no** information about what you're providing as the content of `Range`. "Please help me. I'm not going to tell you exactly what I'm doing, but it's not working." makes help really hard to provide. So does "I'm passing something in a `FORMATRANGE` (but I won't tell you what so you can see if it's correct), but it's not working. What's wrong?". – Ken White Feb 29 '12 at 01:45
  • @KenWhite Ok, since you ask ... Range.hdc := aCanvas.Handle; Range.hdcTarget := aCanvas.Handle; LogX := GetDeviceCaps(Range.hdc, LOGPIXELSX); LogY := GetDeviceCaps(Range.hdc, LOGPIXELSY); Range.rc.Left := x * 1440 div LogX; Range.rc.Right := (x+re.ClientWidth) * 1440 div LogX; // (1440=twips/inch) Range.rc.Top := y * 1440 div LogY; Range.rc.Bottom := 5000 * 1440 div LogY; // Some bigish number Range.rcPage := Range.rc; Range.chrg.cpMin := 0; Range.chrg.cpMax := -1; – Terry Feb 29 '12 at 03:32
  • I've got full control of position, font, justification, size etc. Even transparency. The only issue is that the background is always rendered as white regardless of color of the richedit ('re' in the code above which I change to 'myrichedit' in the original question). – Terry Feb 29 '12 at 04:11
  • My immediate reaction is that this is not strange at all, because the `Color` property of the `TRichEdit` 'feels' like a purely on-screen visual thing (like the border around the control), and should have nothing to do with the document inside the rich-edit control. (Not quite sure how to achieve the background on print, though. Never been doing much printing using the rich edit.) – Andreas Rejbrand Feb 29 '12 at 05:53

1 Answers1

1

What I've found is that a solution to this is that you can set the background of individual characters with the code (before adding the text to the richedit) ...

var
  Format: CHARFORMAT2;
begin
...
 myrichedit.SelStart:=myrichedit.GetTextLen;
 FillChar(Format, SizeOf(Format), 0);
 with Format do begin
     cbSize := SizeOf(Format);
     dwMask := CFM_BACKCOLOR;
     crBackColor := charbackgroundcolor;
     myrichedit.Perform(EM_SETCHARFORMAT, SCF_SELECTION, Longint(@Format));
 end;
 myrichedit.SetText:='Hello';

... but to get a background color for the whole block of text then do this to draw the text ...

var
  size : Tsize;
  Range: TFormatRange;
  Rect: TRect;
  LogX, LogY : Integer;
  bm : tbitmap;
  aCanvas : TCanvas;
  ExStyle: DWord;
begin
  aCanvas:=Printer.Canvas;

  Range.hdc := aCanvas.Handle;
  Range.hdcTarget := aCanvas.Handle;

  LogX := GetDeviceCaps(Range.hdc, LOGPIXELSX);
  LogY := GetDeviceCaps(Range.hdc, LOGPIXELSY);

  Range.rc.Left := x * 1440 div LogX;
  Range.rc.Right := (x+myrichedit.ClientWidth) * 1440 div LogX; // (1440=twips/inch)
  Range.rc.Top := y * 1440 div LogY;
  Range.rc.Bottom := 5000 * 1440 div LogY; // Some bigish number
  Range.rcPage := Range.rc;
  Range.chrg.cpMin := 0;
  Range.chrg.cpMax := -1;  
  myrichedit.Perform(EM_FORMATRANGE, 0, Longint(@Range)); // Measure the formatted text
  rect:=Range.rc;
  rect.Left:=Range.rc.Left * LogX div 1440;
  rect.Top:=Range.rc.Top * LogY div 1440;
  rect.Right:=Range.rc.Right * LogX div 1440;
  rect.Bottom:=Range.rc.Bottom * LogY div 1440;
  acanvas.Brush.Color:=myblockcolor;
  acanvas.FillRect(rect); // Fill the background rectangle

  ExStyle := GetWindowLong(re.Handle, GWL_EXSTYLE); // Draw richedit transparently over coloured area
  ExStyle := ExStyle or WS_EX_TRANSPARENT;
  SetWindowLong(re.Handle, GWL_EXSTYLE, ExStyle);
  myrichedit.Perform(EM_FORMATRANGE, 1, Longint(@Range));  
end;
Terry
  • 274
  • 1
  • 4
  • 16
  • I know it is too old, but... nice hack, though! By the way do not forget to restore previous ExStyle of `RichEdit` after you end with `FormatRange` because it is not very well for `Edit` control to be transparent all the time, and after all, the content of `RichEdit` with that Window-style get messy – Josef Švejk Jun 09 '22 at 06:55