|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Version 2.0 released!After many requests and many new features added to the initial version, here
is version 2.0 of FormPrinting. A lot of improvements have been made in this
totally rewritten version. The main one is complete management of controls
growing over many pages. That is UpdateRelease 2.1 : property added for horizontal alignment.
Release 2.2 : bugs fixed. (1) Extension problem when top position of a control equal bottom position of above control that grow. This problem arrive when docking is used. (2) Little print error in
IntroductionFormPrinting is useful to produce a report directly from a form containing desired data. There are tools to print grids, trees, but I saw nothing to print a form. It's possible to do a print screen, but this gives a cheap looking report. This tool prints any form in a manner that looks like a report. It create
pages by using a Using the codeTo use it, just call the Dim fp As New FormPrinting(Me)
fp.Print() 'Print to printer
fp.PrintToTifFile("myTiffFileName") 'Print to tif file
By passing
However, you can pass any type of Windows control to the constructor. For
example, you can send only a The class takes care of some control properties like The following properties of the public bool TextBoxBoxed = false;
// box around TextBox controls
public bool TabControlBoxed = true;
// box around TabControl controls
public bool LabelInBold = true;
// Print all labels in bold
public bool PrintPreview = true;
// enabled Print preview instead of direct printing
public bool DisabledControlsInGray = false;
// Color for disabled controls
public bool PageNumbering = false;
//If true, reserve space at the bottom of
//each page and print page number
public string PageNumberingFormat = "Page {0}";
// String format for page number
public OrientationENum Orientation = OrientationENum.Automatic;
// choose print orientation (Automatic, Protrait or Landscape)
public ControlPrinting DelegatePrintingReportTitle;
// Function that will print report title
public Single TopMargin = 0;
//If 0, use default margin, else use this (1/100 inch)
public Single BottomMargin = 0;
//If 0, use default margin, else use this (1/100 inch)
It's possible to activate printing of customized controls that have a
fp.AddTextBoxLikeControl("DateTimeSlicker")
ImprovementsThis a list of addition made in version 2.0. Most of them are discussed in this article :
Providing your own printing functionPrinting functions for each control type, including fp.AddDelegateToPrintControl("FlexGrid", _
AddressOf FlexGridPrinting.PrintIt)
This will cause To replace the internal function used to print the title of the report,
assign yours to the public variable fp.DelegatePrintingReportTitle = AddressOf MyOwnPrintReportTitle
Printing function must correspond to the following signature : public delegate void ControlPrinting(
System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls);
In most case, set
MultiPage managementThe Drawing must always be done in a print unit. If there is not enough space at
the bottom of the current page to print the unit, this one will be print at the
top of next page. Print units below it must be push down. This is handled by the
Print of more than one page is pretty tricky with This process also save bitmap memory usage when print to a Tif file. Each page use the same bitmap. Frames (pages) are added to the tif file at each pass. Look at this code snippet demonstrating printing of an item in a
extendedHeight = mp.BeginPrintUnit(yItem, lb.ItemHeight);
mp.DrawString(lb.Text, printFont, _Brush, x, yItem,
lb.Width, lb.ItemHeight);
mp.EndPrintUnit();
The Control growingI'm specially proud of this feature that works very fine. The code I wrote
for this is fairly short and robust at the same time. It take care of any
controls position below, above or side by side with another one. It also
calculate the new height of container controls like The Combination of Control expansion, recursive printing and
The basic logic is that a control is push down (Y position increased) to keep his vertical distance with the bottom of the nearest control above him. Here is the only section of code that do all of this. It's in
Note : "Controls" is an array of contained controls sorted by Y position. For
example, it can refer to all controls inside a // ************************************************************
// This loop over child controls calculate position of them.
// Algorithm take care of controls that expand besides and above.
// It keep an arraylist of original and printed (after expansion) bottom
// position of expanded control.
// So control is push down if it was originally below expanded controls
// *************************************************************
for (int i = 0; i < nbCtrl; i++)
{
// Set y position of control depending of extension of controls above him
Single pushDownHeight = 0;
foreach (Element e in extendedYPos)
if (controls[i].Location.Y > e.originalBottom) //completely under it
{
if (e.totalPushDown > pushDownHeight)
pushDownHeight = e.totalPushDown;
}
Single cp = controls[i].Location.Y + pushDownHeight;
Single extendedHeight;
PrintControl(controls[i], mp,
x + controls[i].Location.X, y + cp, out extendedHeight);
if (extendedHeight > 0)
{
//Keep extention with y position
Element e = new Element();
e.originalBottom = controls[i].Location.Y + controls[i].Height;
e.printedBottom = cp + controls[i].Height + extendedHeight;
extendedYPos.Add(e);
}
}
// same computation for bottom of container control. Its bottom line is
// below all child controls. So it is extended the same as the most pushed
// child control.
globalExtendedHeight = 0;
foreach (Element e in extendedYPos)
if (e.totalPushDown > globalExtendedHeight)
globalExtendedHeight = e.totalPushDown;
}
private class Element
{
public Single originalBottom;
public Single printedBottom;
public Single totalPushDown
{get {return printedBottom - originalBottom;} }
}
Behind the scene of control printingSome type of control was more difficult to format than other. In this section I explain how I solved some problems. For multiline For For DataGridTableStyle myGridTableStyle;
if (dg.TableStyles.Count == 0)
{
myGridTableStyle = new DataGridTableStyle();
dg.TableStyles.Add(myGridTableStyle);
}
string caption = dg.TableStyles[0].GridColumnStyles[i].HeaderText;
Another job to do was juggling with alignment. For DrawingDrawing of controls is made via a public void DrawRectangle(Pen pen, Single x,
Single y, Single w, Single h)
{
if (PrintUnitIsInCurrentPage())
{
Single yPage = _ConvertToPage(y);
_G.DrawRectangle(pen, x, yPage, w, h);
}
}
The To save an image, a Graphics g = Graphics.FromImage(bitmapAllPages);
To obtain a multiframe image, bitmaps are added together with
To print the report, a LimitationsNot all properties are considered when printing controls. As an example,
Using the DemoThe Demo Form contain many
The Demo also demonstrate how you can provide your own print function to the
class. I use this Form to test the | ||||||||||||||||||||