Page Index Toggle Pages: 1 Send TopicPrint
Normal Topic RichTextBox (in ControlHost) and CreateImage (Read 5542 times)
Smitty
YaBB Newbies
*
Offline



Posts: 6
Joined: Sep 23rd, 2006
RichTextBox (in ControlHost) and CreateImage
Sep 24th, 2006 at 9:14am
Print Post  
Hi!

I'm trying RichTextBox controls hosted in ControlHost nodes. It seems they don't render correct when calling flowChart.CreateImage(). Only an empty box (the box of the ControlHost I suppose) is rendered within the image, not the content of the RichTextBox.

Same for flowChart.PrintPreview().

I tried it with classes Label and Button. They are rendering correct, so I think it's some problem especially with RichTextBox.

Thank you for your help!

  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: RichTextBox (in ControlHost) and CreateImage
Reply #1 - Sep 25th, 2006 at 5:20am
Print Post  
Hi!

When on the screen, hosted controls paint themselves in their own windows. When printing or exporting images, FlowChart.NET can render only native .NET controls, which draw themselves in the Control.OnPaint method. In that case FlowChart.NET passes to the hosted controls the Graphics object associated with a printer or an image.

RichTextBox and several other controls (e.g. the browser control) are merely wrappers around Win32 or COM controls; they do not implement OnPaint but rely on the underlying Win32/COM objects to do the painting. In that case, you will probably see only the shadow of the ControlHost node in the exported image or printed page.

FlowChart.NET raises the PaintControlHost event when it needs to draw such controls on printer/image Graphics - you can handle the event and provide some representation of the control data yourself. Here is a code snippet from the help file that shows how you could handle the event:

Code
Select All
private void fc_PaintControlHost(object sender, MindFusion.FlowChartX.ControlPaintArgs e)
{
  // if we host TextBox controls, paint a close representation of their
  // contents when rendering to printer/preview/overview etc.

  if (e.controlHost.Control is TextBox)
  {
    TextBox tb = (TextBox)e.controlHost.Control;

    System.Drawing.Brush wb = new System.Drawing.SolidBrush(Color.White);
    e.Graphics.FillRectangle(wb, e.PaintRect);
    wb.Dispose();

    // now you can't distinguish that from a real TextBox
    System.Drawing.Brush bb = new System.Drawing.SolidBrush(Color.Black);
    Font font = new Font("Arial", 2, GraphicsUnit.World);
    e.Graphics.DrawString(tb.Text, font, bb, e.PaintRect);
    font.Dispose();
    bb.Dispose();
  }
}

 



Stoyan
  
Back to top
 
IP Logged
 
Smitty
YaBB Newbies
*
Offline



Posts: 6
Joined: Sep 23rd, 2006
Re: RichTextBox (in ControlHost) and CreateImage
Reply #2 - Oct 16th, 2006 at 11:02am
Print Post  
Thank You for your help!

Tried this and now I got the next problem. It's not a problem of FlowChart, but perhaps someone can help anyway.

Microsoft's RichTextBox control has no direct method for painting or printing. There is an article at MSDN that shows how to print anyway by using some window messages.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwinforms/html...

I tried to adapt that VB function for using it to draw on the Graphics within the PaintControlHost event. It's working somehow, but the scaling doesn't fit. The boxes have wrong size and appear in wrong place and it doesn't seem to be a linear offset. By just multiplying the Rects with some factor you can achieve to fit one RichTextBox in the correct place, but not the others.

Perhaps someone can help? ???

The PaintControlHost event:
Code
Select All
private void flowChart1_PaintControlHost(object sender, ControlPaintArgs e) {
		if (e.ControlHost.Control is ExtendedRichTextBox.RichTextBoxPrintCtrl) {
		    ExtendedRichTextBox.RichTextBoxPrintCtrl rtb = (ExtendedRichTextBox.RichTextBoxPrintCtrl) e.ControlHost.Control;
		    rtb.GetImage(e.Graphics, e.PaintRect, flowChart1.DocExtents);
		}
} 



The adpated VB function:
Code
Select All
' Render the contents of the RichTextBox for printing
    ' Return the last character printed + 1 (printing start from this point
for next page)
    Public Function GetImage(ByVal e As Graphics, ByVal drawrect As
RectangleF, ByVal devRect As RectangleF) As Integer

	  ' Mark starting and ending character
	  Dim cRange As CHARRANGE
	  cRange.cpMin = 0
	  cRange.cpMax = Me.TextLength - 1

	  ' Calculate the area to render and print
	  Dim rectToPrint As RECT
	  rectToPrint.Top = drawrect.Top * AnInch
	  rectToPrint.Bottom = drawrect.Bottom * AnInch
	  rectToPrint.Left = drawrect.Left * AnInch
	  rectToPrint.Right = drawrect.Right * AnInch

	  ' Calculate the size of the page
	  Dim rectPage As RECT
	  rectPage.Top = devRect.Top * AnInch
	  rectPage.Bottom = devRect.Bottom * AnInch
	  rectPage.Left = devRect.Left * AnInch
	  rectPage.Right = devRect.Right * AnInch

	  Dim hdc As IntPtr = e.GetHdc()

	  Dim fmtRange As FORMATRANGE
	  fmtRange.chrg = cRange		     ' Indicate character from to
character to
	  fmtRange.hdc = hdc			   ' Use the same DC for
measuring and rendering
	  fmtRange.hdcTarget = hdc		   ' Point at printer hDC
	  fmtRange.rc = rectToPrint		  ' Indicate the area on page
to print
	  fmtRange.rcPage = rectPage		 ' Indicate whole size of page

	  Dim res As IntPtr = IntPtr.Zero

	  Dim wparam As IntPtr = IntPtr.Zero
	  wparam = New IntPtr(1)

	  ' Move the pointer to the FORMATRANGE structure in memory
	  Dim lparam As IntPtr = IntPtr.Zero
	  lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange))
	  Marshal.StructureToPtr(fmtRange, lparam, False)

	  ' Send the rendered data for printing
	  res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam)

	  ' Free the block of memory allocated
	  Marshal.FreeCoTaskMem(lparam)

	  ' Release the device context handle obtained by a previous call
	  e.ReleaseHdc(hdc)

	  ' Return last + 1 character printer
	  Return res.ToInt32()
End Function 

  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: RichTextBox (in ControlHost) and CreateImage
Reply #3 - Oct 16th, 2006 at 1:00pm
Print Post  
Hi,

What does AnInch specify? By default you get the box coordinates in millimeters, so if AnInch is measured in pixels, you will get incorrect results.

Stoyan
  
Back to top
 
IP Logged
 
Smitty
YaBB Newbies
*
Offline



Posts: 6
Joined: Sep 23rd, 2006
Re: RichTextBox (in ControlHost) and CreateImage
Reply #4 - Oct 16th, 2006 at 1:49pm
Print Post  
AnInch ist just a constant factor of 14.4

Comment in original code is:

' Convert between 1/100 inch (unit used by the .NET framework)
' and twips (1/1440 inch, used by Win32 API calls)

  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: RichTextBox (in ControlHost) and CreateImage
Reply #5 - Oct 16th, 2006 at 6:31pm
Print Post  
Ok, an inch equals 2.54 cm, so if you haven't changed the MeasureUnit, try how that will work with AnInch = 25.4 (mm).

Stoyan
  
Back to top
 
IP Logged
 
Smitty
YaBB Newbies
*
Offline



Posts: 6
Joined: Sep 23rd, 2006
Re: RichTextBox (in ControlHost) and CreateImage
Reply #6 - Oct 17th, 2006 at 11:54am
Print Post  
Hi!

I already tried a higher factor. But the divergence isn't linear.

Original screenshot from within FlowChart:
bts.wotok.de/diagramm2.gif

Image from image export:
bts.wotok.de/diagramm.gif

As you can see it isn't the same discrepance for x and y offset, and it isn't the same for the two RichTextBoxes... I'm really confused  Undecided
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: RichTextBox (in ControlHost) and CreateImage
Reply #7 - Oct 17th, 2006 at 12:18pm
Print Post  
Try passing the controlHost.BoundingRect as a devRect parameter to that method. If that does not work, please email me your test project and our developers will try to find what's wrong.

Stoyan
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: RichTextBox (in ControlHost) and CreateImage
Reply #8 - Oct 18th, 2006 at 11:22am
Print Post  
Hi,

We've made the following changes:

In the form -

Code
Select All
private void flowChart1_PaintControlHost(object sender, ControlPaintArgs e)
{
  if (e.ControlHost.Control is ExtendedRichTextBox.RichTextBoxPrintCtrl)
  {
    FlowChart temp = new FlowChart();
    temp.MeasureUnit = GraphicsUnit.Inch;
    RectangleF anInch = new RectangleF(0, 0, 1, 1);
    Rectangle devInch = temp.DocToClient(anInch);
    float dpi = devInch.Width;

    ExtendedRichTextBox.RichTextBoxPrintCtrl rtb = (ExtendedRichTextBox.RichTextBoxPrintCtrl)e.ControlHost.Control;
    Rectangle paintRect = flowChart1.DocToClient(e.PaintRect);
    Rectangle pageRect = flowChart1.DocToClient(flowChart1.DocExtents);
    rtb.GetImage(e.Graphics, paintRect, pageRect, dpi);
  }
}
 



and in the extended control -

Code
Select All
  Public Function GetImage(ByVal e As Graphics, ByVal drawrect As Rectangle, ByVal devRect As Rectangle, ByVal dpi As Single) As Integer
        ' Mark starting and ending character
        Dim cRange As CHARRANGE
        cRange.cpMin = 0
        cRange.cpMax = Me.TextLength

        ' Calculate the area to render and print in twips
        Dim rectToPrint As RECT
        rectToPrint.Top = drawrect.Top / dpi * 1440
        rectToPrint.Bottom = drawrect.Bottom / dpi * 1440
        rectToPrint.Left = drawrect.Left / dpi * 1440
        rectToPrint.Right = drawrect.Right / dpi * 1440

        ' Calculate the size of the page in twips
        Dim rectPage As RECT
        rectPage.Top = devRect.Top / dpi * 1440
        rectPage.Bottom = devRect.Bottom / dpi * 1440
        rectPage.Left = devRect.Left / dpi * 1440
        rectPage.Right = devRect.Right / dpi * 1440
...
 



Now the coordinate calculations seem correct. There is only one problem remaining - the rich text control paints only the part of the control where there is some text, so you would first have to use Graphics.FillRect to fill the background.

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Smitty
YaBB Newbies
*
Offline



Posts: 6
Joined: Sep 23rd, 2006
Re: RichTextBox (in ControlHost) and CreateImage
Reply #9 - Oct 18th, 2006 at 4:03pm
Print Post  
Thank You! That really helped a lot!  Cheesy

The background thing is done by adding the following line to the PaintControlHost event:

e.Graphics.FillRectangle(new System.Drawing.SolidBrush(rtb.BackColor), e.PaintRect);

So it's now:


Code
Select All
...
		    Rectangle pageRect = flowChart1.DocToClient(flowChart1.DocExtents);
		    e.Graphics.FillRectangle(new System.Drawing.SolidBrush(rtb.BackColor), e.PaintRect);
		    rtb.GetImage(e.Graphics, paintRect, pageRect, dpi);
...
 

  
Back to top
 
IP Logged
 
Page Index Toggle Pages: 1
Send TopicPrint