I have to print shipping labels for the products our company manufactures.
To help give myself a feel for how these labels will turn out, I design them using a Windows Form. This allows me to position my text, get the fonts set right, etc. using Label controls, add a custom BarCode control, and get "fancy" with Panel controls to group items into boxes.
Each page holds two (2) labels.
When my code prints a label document, I request either 2, 4 or 6 copies. Occasionally, the Print Preview is used as well. In this case, I have to reset the number of labels created.
However, when the documents print:
Does anyone see a pattern? I do not.
This is my Print command:
public int Print(string docName, int rows, int columns, int copies) {
short shortCopies = (short)copies;
LabelsHorizontal = rows;
LabelsVertical = columns;
Size docSize = PrintPreview.Document.DefaultPageSettings.Bounds.Size;
float height = 0.8F * Screen.PrimaryScreen.WorkingArea.Size.Height;
float width = (height * docSize.Width) / docSize.Height;
Size winSize = new Size((int)width, (int)height);
PrintPreview.Height = winSize.Height;
PrintPreview.Width = winSize.Width;
if (!String.IsNullOrEmpty(docName)) {
PrintPreview.Document.DocumentName = docName;
}
PrintPreview.Document.PrinterSettings.Copies = shortCopies;
PrintPreview.SettingsFilename = Settings.PageSettingsLocation;
if (!PrintPreview.PrinterSelected) {
if (PrintPreview.ShowPrinterSelectDialog() != DialogResult.OK) {
return 0;
}
}
labelQtyPrinted = 0;
if (ShowPrintPreview) {
PrintPreview.ShowDialog();
} else {
PrintPreview.PrintDocument();
}
return labelQtyPrinted;
}
// Resets the Label Count between PrintPreview and Print
private void PrintPreview_OnPrintClicked(object sender, EventArgs e) {
labelQtyPrinted = 0;
}
I had to write a custom PrintPreview class that takes the PrintPreviewDialog as a base class so that I could override its Print button with this printButton_Click method:
// Handles the Printing of the Document
internal void printButton_Click(object sender, EventArgs e) {
if (OnPrintClicked != null) {
OnPrintClicked(sender, e); // this resets my labelQtyPrinted value shown above
}
Document.Print();
printed = true;
Close();
}
In the Print method (the first snippet of code), PrintPreview.PrintDocument() is just code that calls the printButton_Click event.
My PrintPageEventHandler is shown below:
private void Document_Printed(object sender, PrintPageEventArgs e) {
if (PrintPreview.Document.PrinterSettings.Copies <= labelQtyPrinted) {
throw new Exception("Run Away Printer");
}
float scale;
SizeF pageSize = new SizeF(
PrintPreview.Document.DefaultPageSettings.PaperSize.Width,
PrintPreview.Document.DefaultPageSettings.PaperSize.Height
);
Margins m = PrintPreview.Document.DefaultPageSettings.Margins;
float printableHeight = pageSize.Height - (m.Top + m.Bottom);
float printableWidth = pageSize.Width - (m.Left + m.Right);
if (printableWidth < printableHeight) {
if (labelSize.Width < labelSize.Height) {
float r1 = (printableWidth) / labelSize.Width;
float r2 = (printableHeight) / labelSize.Height;
scale = (r1 < r2) ? r1 : r2;
} else {
scale = (printableWidth) / labelSize.Width;
}
} else {
if (labelSize.Width < labelSize.Height) {
scale = (printableHeight) / labelSize.Height;
} else {
float r1 = (printableWidth) / labelSize.Width;
float r2 = (printableHeight) / labelSize.Height;
scale = (r1 < r2) ? r1 : r2;
}
}
float lh = scale * labelSize.Height;
float lw = scale * labelSize.Width;
float ml = scale * m.Left;
float mt = scale * m.Top;
Graphics G = e.Graphics;
G.SmoothingMode = smoothMode;
G.TextRenderingHint = TextRenderingHint.AntiAlias;
for (int i = 0; i < LabelsHorizontal; i++) {
float dx = i * (lw + ml); // Horizontal shift * scale
for (int j = 0; j < LabelsVertical; j++) {
float dy = j * (lh + mt); // Vertical shift * scale
#region ' Panels '
foreach (Panel item in panels) {
float h = scale * item.Size.Height;
float w = scale * item.Size.Width;
float x = (ml + dx) + scale * item.Location.X;
float y = (mt + dy) + scale * item.Location.Y;
using (SolidBrush b = new SolidBrush(item.BackColor)) {
G.FillRectangle(b, x, y, w, h);
}
using (Pen p = new Pen(Brushes.Black)) {
G.DrawRectangle(p, x, y, w, h);
}
}
#endregion
#region ' Logo '
if (logo != null) {
float h = scale * logo.Height;
float w = scale * logo.Width;
float x = (ml + dx) + scale * logoPt.X;
float y = (mt + dy) + scale * logoPt.Y;
G.DrawImage(logo, x, y, w, h);
}
#endregion
#region ' Labels '
foreach (Label item in labels) {
float h = scale * item.Size.Height;
float w = scale * item.Size.Width;
float x = (ml + dx) + scale * item.Location.X;
float y = (mt + dy) + scale * item.Location.Y;
Color c = PrintPreview.Document.DefaultPageSettings.Color ? item.ForeColor : Color.Black;
Font font = new Font(item.Font.FontFamily, scale * item.Font.Size, item.Font.Style);
using (SolidBrush b = new SolidBrush(c)) {
StringFormat format = GetStringFormatFromContentAllignment(item.TextAlign);
format.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
format.Trimming = StringTrimming.None;
PointF locationF = new PointF(x, y);
SizeF size = new SizeF(w, h);
RectangleF r = new RectangleF(locationF, size);
G.DrawString(item.Text, font, b, r, format);
}
}
#endregion
#region ' Barcodes '
foreach (AcpBarcodeControl item in barcodes) {
Image img = item.GetBarcodeImage(item.BarcodeText);
if (img != null) {
float h = scale * item.Size.Height;
float w = scale * item.Size.Width;
float x = (ml + dx) + scale * item.Location.X;
float y = (mt + dy) + scale * item.Location.Y;
G.DrawImage(img, x, y, w, h);
}
}
#endregion
labelQtyPrinted++;
if (labelQtyPrinted == PrintPreview.Document.PrinterSettings.Copies) {
e.HasMorePages = false;
return;
}
}
e.HasMorePages = (labelQtyPrinted < PrintPreview.Document.PrinterSettings.Copies);
}
}
All in all, it works very well. The "Run Away Printer" Exception is never thrown.
So, why are so many copies being made?
The Printer is an HP LaserJet 4050, if that makes any difference.
I GOT IT!
Yippie!
OK, if anyone cares, here's the deal: I needed to print two (2) labels per page.
What I had to do was calculate how many pages to print, using the number of labels to be printed vertically and horizontally.
I added the variable labelsRequested and changed the existing variable labelQtyPrinted to be called labelsPrinted:
private int labelsPrinted;
private int labelsRequested;
My public Print method was changed to this:
public int Print(string docName, int rows, int columns, int copies) {
LabelsHorizontal = rows;
LabelsVertical = columns;
if (!String.IsNullOrEmpty(docName)) {
PrintPreview.Document.DocumentName = docName;
}
labelsRequested = copies;
//PrintPreview.Document.PrinterSettings.Copies = (short)copies;
PrintPreview.SettingsFilename = Settings.PageSettingsLocation;
if (!PrintPreview.PrinterSelected) {
if (PrintPreview.ShowPrinterSelectDialog() != DialogResult.OK) {
return 0;
}
}
if (ShowPrintPreview) {
Size docSize = PrintPreview.Document.DefaultPageSettings.Bounds.Size;
float height = 0.8F * Screen.PrimaryScreen.WorkingArea.Size.Height;
float width = (height * docSize.Width) / docSize.Height;
Size winSize = new Size((int)width, (int)height);
PrintPreview.Height = winSize.Height;
PrintPreview.Width = winSize.Width;
PrintPreview.Document.PrinterSettings.Copies = (short)labelsRequested; // this may cause problems
PrintPreview.ShowDialog();
} else {
PrintPreview.PrintDocument();
}
return labelsPrinted;
}
Now, instead of adding the print_Click event handler like I had before, I have wired up the Document's BeginPrint and EndPrint like so:
void Document_BeginPrint(object sender, PrintEventArgs e) {
labelsPrinted = 0;
float fPerPage = LabelsHorizontal * LabelsVertical;
if (1 < fPerPage) {
float fQty = labelsRequested;
float fTotal = fQty / fPerPage;
PrintPreview.Document.PrinterSettings.Copies = (short)fTotal;
}
}
void Document_EndPrint(object sender, PrintEventArgs e) {
Printed = (labelsPrinted == labelsRequested);
}
The key here, though, apparently came from me trying to set the HasMorePages value in the PrintPage event handler.
"Why?" you ask. Because I was only printing multiple copies of the same, 1-sheet sized document. If my one document were to span multiple pages, then I would need to ensure that HasMorePages was set.
Without further ado, here is my PrintPage event handler (note that a lot of this code is very universal and can be easily edited to work for others):
private void Document_Printed(object sender, PrintPageEventArgs e) {
float scale;
SizeF pageSize = new SizeF(
PrintPreview.Document.DefaultPageSettings.PaperSize.Width,
PrintPreview.Document.DefaultPageSettings.PaperSize.Height
);
Margins m = PrintPreview.Document.DefaultPageSettings.Margins;
float printableHeight = pageSize.Height - (m.Top + m.Bottom);
float printableWidth = pageSize.Width - (m.Left + m.Right);
if (printableWidth < printableHeight) {
if (labelSize.Width < labelSize.Height) {
float r1 = printableWidth / labelSize.Width;
float r2 = printableHeight / labelSize.Height;
scale = (r1 < r2) ? r1 : r2;
} else {
scale = printableWidth / labelSize.Width;
}
} else {
if (labelSize.Width < labelSize.Height) {
scale = (printableHeight) / labelSize.Height;
} else {
float r1 = printableWidth / labelSize.Width;
float r2 = printableHeight / labelSize.Height;
scale = (r1 < r2) ? r1 : r2;
}
}
float lh = scale * labelSize.Height;
float lw = scale * labelSize.Width;
float ml = scale * m.Left;
float mt = scale * m.Top;
Graphics G = e.Graphics;
G.SmoothingMode = smoothMode;
G.TextRenderingHint = TextRenderingHint.AntiAlias;
for (int i = 0; (i < LabelsHorizontal) && !e.Cancel; i++) {
float dx = i * (lw + ml); // Horizontal shift * scale
for (int j = 0; (j < LabelsVertical) && !e.Cancel; j++) {
float dy = j * (lh + mt); // Vertical shift * scale
#region ' Panels '
foreach (Panel item in panels) {
float h = scale * item.Size.Height;
float w = scale * item.Size.Width;
float x = (ml + dx) + scale * item.Location.X;
float y = (mt + dy) + scale * item.Location.Y;
using (SolidBrush b = new SolidBrush(item.BackColor)) {
G.FillRectangle(b, x, y, w, h);
}
using (Pen p = new Pen(Brushes.Black)) {
G.DrawRectangle(p, x, y, w, h);
}
}
#endregion
#region ' Logo '
if (logo != null) {
float h = scale * logo.Height;
float w = scale * logo.Width;
float x = (ml + dx) + scale * logoPt.X;
float y = (mt + dy) + scale * logoPt.Y;
G.DrawImage(logo, x, y, w, h);
}
#endregion
#region ' Labels '
foreach (Label item in labels) {
float h = scale * item.Size.Height;
float w = scale * item.Size.Width;
float x = (ml + dx) + scale * item.Location.X;
float y = (mt + dy) + scale * item.Location.Y;
Color c = PrintPreview.Document.DefaultPageSettings.Color ? item.ForeColor : Color.Black;
Font font = new Font(item.Font.FontFamily, scale * item.Font.Size, item.Font.Style);
using (SolidBrush b = new SolidBrush(c)) {
StringFormat format = GetStringFormatFromContentAllignment(item.TextAlign);
format.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
format.Trimming = StringTrimming.None;
PointF locationF = new PointF(x, y);
SizeF size = new SizeF(w, h);
RectangleF r = new RectangleF(locationF, size);
G.DrawString(item.Text, font, b, r, format);
}
}
#endregion
#region ' Barcodes '
foreach (AcpBarcodeControl item in barcodes) {
Image img = item.GetBarcodeImage(item.BarcodeText);
if (img != null) {
float h = scale * item.Size.Height;
float w = scale * item.Size.Width;
float x = (ml + dx) + scale * item.Location.X;
float y = (mt + dy) + scale * item.Location.Y;
G.DrawImage(img, x, y, w, h);
}
}
#endregion
labelsPrinted++;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With