I got a windows form which has more than one page of mainly labels and textboxes, I'm trying to keep the font that i have in the winform already, so far I'm able to print the first page, but when i try to add the rest of the controls it does all sort of weird stuff this is the part of my code where i'm putting everything to print but not all the controls in the panel show in the print preview. So i found out that the controls in the panel are not in order and what i need to do is create the number of printing pages first then put the controls in those printing pages. any help on trying to create the print pages first to add the controls to it. it will always be 4 print pages.
int mainCount = 0;
public void printStuff(System.Drawing.Printing.PrintPageEventArgs e)
{
Font printFont = new Font("Arial", 9);
int dgX = dataGridView1.Left;
int dgY = dataGridView1.Top += 22;
double linesPerPage = 0;
float yPos = 0;
int count = 0;
float leftMargin = e.MarginBounds.Left;
float topMargin = e.MarginBounds.Top;
float bottomMargin = e.MarginBounds.Bottom;
StringFormat str = new StringFormat();
linesPerPage = e.MarginBounds.Height / printFont.GetHeight(e.Graphics);
Control ctrl;
while ((count < linesPerPage) && (panel1.Controls.Count != mainCount))
{
ctrl = panel1.Controls[mainCount];
yPos = topMargin + (count * printFont.GetHeight(e.Graphics));
mainCount++;
count++;
if (ctrl is Label)
{
e.Graphics.DrawString(ctrl.Text, printFont, Brushes.Black, ctrl.Left + 5, ctrl.Top + 40);
}
else if (ctrl is TextBox)
{
e.Graphics.DrawString(ctrl.Text, printFont, Brushes.Black, ctrl.Left + 5, ctrl.Top + 40);
e.Graphics.DrawRectangle(Pens.Black, ctrl.Left, ctrl.Top + 40, ctrl.Width, ctrl.Height);
}
}
if (count > linesPerPage)
{
e.HasMorePages = true;
}
else
{
e.HasMorePages = false;
}
}
//Print
private void exportFileToolStripMenuItem_Click(object sender, EventArgs e)
{
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
printStuff(e);
}
It seems to me that the problem is that on subsequent pages you are not subtracting the "page offset" form the control Top positions when printing. You are essentially trying to use the screen coordinates of the controls when placing them on the printed page which obviously only works correctly for the first page. On subsequent pages you need to map the screen coordinates by subtracting a quantity which is the equivalent of the "total-printed-surface-so-far"..
You will want to modify this line for instance:
e.Graphics.DrawString(ctrl.Text, printFont, Brushes.Black, ctrl.Left + 5, ctrl.Top + 40);
to something like this:
e.Graphics.DrawString(ctrl.Text, printFont, Brushes.Black, ctrl.Left + 5, ctrl.Top + 40 - pageOffset);
where the pageOffset is a variable that should be computed for each page, based on the Height of the printable area: pageOffset = currentPageNumber * heightOfPrintableArea so you will also need to maintain a variable for the number of pages printed, similar to the mainCount
Of course, the same would apply to the other branch of your if statement:
e.Graphics.DrawString(ctrl.Text, printFont, Brushes.Black, ctrl.Left + 5, ctrl.Top + 40 - pageOffset);
e.Graphics.DrawRectangle(Pens.Black, ctrl.Left, ctrl.Top + 40 - pageOffset, ctrl.Width, ctrl.Height);
Related
I am trying to print a receipt in my windowsforms application. I have written some test code to run and print lines from 0 to 100. My problem is that it is printing until line 45, and it is not giving any error. I have a thermal printer xPrinter xp-80c, on this printer the max length of the paper is 30cm. And when printing to pdf it is only printing on 1 page.
Can anyone please help here and tell what is wrong.
Thank you in advance.
public static void printNewMethodFromVideoDeleteMeWhenDone()
{
PrintDialog printDialog = new PrintDialog();
PrintDocument printDocument = new PrintDocument();
printDialog.Document = printDocument;
printDocument.PrintPage += printDocument3_PrintPage;
DialogResult result = printDialog.ShowDialog();
if(result == DialogResult.OK)
{
printDocument.Print();
}
}
private static void printDocument3_PrintPage(object sender, PrintPageEventArgs e)
{
try
{
Graphics graphic = e.Graphics;
Font font = new Font("Courier New", 12);
float fontHeight = font.GetHeight();
SolidBrush brush = new SolidBrush(Color.Black);
int startX = 10;
int startY = 10;
int offset = 40;
graphic.DrawString("Welcome to the shop", new Font("Courier New", 16), brush, startX, startY);
for (int i = 0; i < 100; i++)
{
string productDescription = "Some text " + i.ToString().PadRight(30);
string productTotal = string.Format("{0:c}", i.ToString());
string line = productDescription + productTotal;
graphic.DrawString(line, font, new SolidBrush(Color.Black), startX, startY + offset);
offset = offset + (int)fontHeight + 5;
}
offset = offset + 20;
graphic.DrawString("Total To Pay".PadRight(30) + string.Format("{0:c}", 100.ToString()), font, brush, startX, startY + offset);
}
catch(Exception ex)
{
// some code here.
}
}
use your C# programming in loop to build a HTML document and use the webBrowser.Print() function to print. This is much more easier.
Call webBrowser.ShowPrintPreview() to adjust the paper and margin to zero.
create a documentReady event for printing the document after the webBrowser finished rendering the document.
webBrowser.DocumentReady += webBrowser_documentReady;
Here is the sample project that demonstrate the idea: http://www.mediafire.com/file/te2lm9sbfvln7bp/WebBrowserPrinter.zip/file
Hi I have a form for pharmacy purchase but the print/confirm button have errors. The error occurs when it is printing. I just found this codes on a tutorial online and I want to use it.
This is the error I got when pdf is printing.
The error is from the float cash = float.Parse(txBCash.Text.Substring(1, 3));
This is the codes
private void btnConfirm_Click(object sender, EventArgs e)
{
PrintDialog printDialog = new PrintDialog();
PrintDocument printDocument = new PrintDocument();
printDialog.Document = printDocument; //add the document to the dialog box...
printDocument.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(CreateReceipt); //add an event handler that will do the printing
//on a till you will not want to ask the user where to print but this is fine for the test envoironment.
DialogResult result = printDialog.ShowDialog();
if (result == DialogResult.OK)
{
printDocument.Print();
}
}
public void CreateReceipt(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
int total = 0;
float cash = float.Parse(txBCash.Text.Substring(1, 3));
float change = 0.00f;
//this prints the reciept
Graphics graphic = e.Graphics;
Font font = new Font("Courier New", 12); //must use a mono spaced font as the spaces need to line up
float fontHeight = font.GetHeight();
int startX = 10;
int startY = 10;
int offset = 40;
graphic.DrawString(" Kwem Drugstore", new Font("Courier New", 18), new SolidBrush(Color.Black), startX, startY);
string top = "Item Name".PadRight(30) + "Price";
graphic.DrawString(top, font, new SolidBrush(Color.Black), startX, startY + offset);
offset = offset + (int)fontHeight; //make the spacing consistent
graphic.DrawString("----------------------------------", font, new SolidBrush(Color.Black), startX, startY + offset);
offset = offset + (int)fontHeight + 5; //make the spacing consistent
float totalprice = 0.00f;
foreach (string item in listViewOrders.Items)
{
//create the string to print on the reciept
string productDescription = item;
string productTotal = item.Substring(item.Length - 6, 6);
float productPrice = float.Parse(item.Substring(item.Length - 5, 5));
//MessageBox.Show(item.Substring(item.Length - 5, 5) + "PROD TOTAL: " + productTotal);
}
change = (cash - totalprice);
//when we have drawn all of the items add the total
offset = offset + 20; //make some room so that the total stands out.
graphic.DrawString("Total to pay ".PadRight(30) + String.Format("{0:c}", totalprice), new Font("Courier New", 12, FontStyle.Bold), new SolidBrush(Color.Black), startX, startY + offset);
offset = offset + 30; //make some room so that the total stands out.
graphic.DrawString("CASH ".PadRight(30) + String.Format("{0:c}", cash), font, new SolidBrush(Color.Black), startX, startY + offset);
offset = offset + 15;
graphic.DrawString("CHANGE ".PadRight(30) + String.Format("{0:c}", change), font, new SolidBrush(Color.Black), startX, startY + offset);
offset = offset + 30; //make some room so that the total stands out.
graphic.DrawString(" Thank-you for your purchase,", font, new SolidBrush(Color.Black), startX, startY + offset);
offset = offset + 15;
graphic.DrawString(" please come back soon!", font, new SolidBrush(Color.Black), startX, startY + offset);
}
}
I don't know if this is correct or if i'm doing it correctly. But please help me resolve this because for our project in our school.
Any type of response is greatly appreciated. Thank you in advance.
Array indexes in C# starts at zero, not at 1. And the second parameter of the Substring method is not the end position but the length of characters to retrieve. So your code asks for 3 characters from the txBCash textbox starting from the second character typed. If you want to get the first three characters then you should write
float cash = float.Parse(txBCash.Text.Substring(0, 3));
But a better approach is through float.TryParse that doesn't trigger an exception when the input is not a valid float. Of course you cannot be sure that your user types just 3 characters in that textbox, so I would remove also the starting and the length limits
float cash = 0.0;
if(!float.TryParse(txBCash.Text, out cash))
MessageBox.Show("Invalid value for cash");
I have a working code, on both the target machine, and my own machine. However, my machine is a W10, and the target is a W7. The code below should draw 5 barcodes on the right half of the page, however, when I use it on the target machine, one of two scenarios happen, depending on how I change the code. If I make the width of the barcode too big, it will go beyond the edge of the page and it will not be readable. If I make the width slightly too small, it resizes the whole barcode, and it becomes to small, again unreadable. I assume that this is a problem with the print drivers in which, they are different for both W10 and W7 (I used the same printer on both machines, same settings as well).
Is there a problem with my code and how do I change it?
private void DocumentDrucker_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
Graphics graphic = e.Graphics;
//SolidBrush brush = new SolidBrush(Color.Black);
Font font = new Font("Courier New", 80, FontStyle.Bold);
Font fontK = new Font("Courier New", 30, FontStyle.Bold);
Font fontKleinst = new Font("Courier New", 15, FontStyle.Bold);
float pageWidth = e.PageSettings.PrintableArea.Width;
float pageHeight = e.PageSettings.PrintableArea.Height;
float fontHeight = font.GetHeight();
int startX = 0;
int startY = 0;
int offsetY = 0;
float imageH = Properties.Resources.pfeilO.Height;
float imageW = Properties.Resources.pfeilO.Width;
graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
//var imagePoint = new Point(Convert.ToInt32(pageWidth * 0.55), offsetY);
var barcodePoint = new Point(Convert.ToInt32(pageWidth * 0.66), 0);
for (; elemente < ZumDrucken.Items.Count; elemente++)
{
var currentItem = ZumDrucken.Items[elemente];
graphic.DrawString(currentItem.Text.Substring(4, 3), fontK, Brushes.Black, startX, startY +offsetY+20);
graphic.DrawString("Typ:"+currentItem.Text.Substring(0,3), fontKleinst, Brushes.Black, startX, (startY + offsetY + 30+fontK.Height));
graphic.DrawString(currentItem.Text.Substring(7), font, Brushes.Black, (startX+75), startY + offsetY);
var currentImage = Properties.Resources.pfeilU;
bool lastCharIsAOne = currentItem.Text[currentItem.Text.Length - 1] == '1';
if (currentItem.Checked == lastCharIsAOne)
{
currentImage = Properties.Resources.pfeilO;
}
graphic.DrawImage(currentImage, Convert.ToInt32((pageWidth * 0.55)), offsetY+20, imageW, imageH);
b.EncodedImage?.Dispose();
//b.Encode(TYPE.CODE128A, "SBD" + currentItem.Text.Substring(0, 3) + currentItem.Text.Substring(4), Color.Black, Color.Transparent,Convert.ToInt32(pageWidth-50), Convert.ToInt32(pageHeight * 0.151));
b.Encode(TYPE.CODE128A, "SBD" + currentItem.Text.Substring(0, 3) + currentItem.Text.Substring(4), Color.Black, Color.Transparent, 570, 135);
barcodePoint.Y = offsetY;
graphic.DrawImage(b.EncodedImage, barcodePoint);
offsetY = offsetY + 163;
if (offsetY >= pageWidth-120)
{
e.HasMorePages = true;
offsetY = 0;
elemente++;
graphic.Dispose();
b.Dispose();
font.Dispose();
fontK.Dispose();
fontKleinst.Dispose();
return;
}
else
{
e.HasMorePages = false;
}
}
graphic.Dispose();
b.Dispose();
font.Dispose();
fontK.Dispose();
fontKleinst.Dispose();
}
Here is also the code where I set all the margins to 0, and change the paper mode to landscape.
private void Drucken_Click(object sender, EventArgs e)
{
DocumentDrucker.DocumentName = "Dokument";
elemente = 0;
DruckDialog.Document = DocumentDrucker;
DocumentDrucker.DefaultPageSettings.Landscape = true;
DocumentDrucker.DefaultPageSettings.Margins.Top = 0;
DocumentDrucker.DefaultPageSettings.Margins.Left = 0;
DocumentDrucker.DefaultPageSettings.Margins.Right = 0;
DocumentDrucker.DefaultPageSettings.Margins.Bottom = 0;
if (DruckDialog.ShowDialog() == DialogResult.OK)
DocumentDrucker.Print();
}
So, I need to print to a laser printer from a windows form application (c#, .net 4) and I've discovered the super "interesting" PrintDocument class and now have code that works, but it looks like this:
private void PrintCollate(vws.custom.production.IndiPackLabel ipl)
{
var pd = new PrintDocument();
pd.DocumentName = "Collate";
var printerSettings = new System.Drawing.Printing.PrinterSettings();
printerSettings.PrinterName = "HP LaserJet 4100";
pd.PrinterSettings = printerSettings;
pd.PrinterSettings.Copies = 1;
_currCollate = ipl;
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
pd.Print();
_currCollate = null;
}
private static vws.custom.production.IndiPackLabel _currCollate;
public void pd_PrintPage(Object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
float linesPerPage = 0;
//int count = 0;
float leftMargin = 20;
float topMargin = 20;
float yPos = topMargin;
var printFontNormal = new System.Drawing.Font("consolas", 10);
var printFontNormalBold = new System.Drawing.Font("consolas", 10, FontStyle.Bold);
float stdFontHeight = printFontNormal.GetHeight(e.Graphics);
var printFontSmall = new System.Drawing.Font("consolas", 8);
float smallFontHeight = printFontSmall.GetHeight(e.Graphics);
linesPerPage = e.MarginBounds.Height / stdFontHeight;
e.Graphics.DrawString(("Order: " + _currCollate.OrderDescription).PadRight(91) + "ORD #:" + _currCollate.OrderNumber, printFontNormal, Brushes.Black, leftMargin, yPos);
yPos += stdFontHeight;
string customerInfo = (_currCollate.Customer.FirstName + " " + _currCollate.Customer.LastName).PadRight(90) + " BAG #" + _currCollate.BagNumber;
e.Graphics.DrawString(customerInfo, printFontNormal, Brushes.Black, leftMargin, yPos);
yPos += stdFontHeight;
yPos += stdFontHeight;
string header = "ITEMNO".PadRight(20) + "ITEM NAME".PadRight(70) + "QTY".PadRight(3);
e.Graphics.DrawString(header, printFontNormalBold, Brushes.Black, leftMargin, yPos);
int itemTotal = 0;
foreach (var item in _currCollate.OrderItems)
{
yPos += stdFontHeight;
string itemLine = item.ItemNo.PadRight(20) + (item.ItemName + " " + item.OptionNames).PadRight(70) + item.Qty.ToString().PadRight(3);
e.Graphics.DrawString(itemLine, printFontNormal, Brushes.Black, leftMargin, yPos);
if (item.Notes.Length > 0)
{
yPos += stdFontHeight;
string notesLine = string.Empty.PadRight(20) + item.Notes;
e.Graphics.DrawString(notesLine, printFontNormal, Brushes.Black, leftMargin, yPos);
}
itemTotal += item.Qty;
}
yPos += stdFontHeight;
string footer = "TOTAL ITEMS: ".PadRight(90) + itemTotal;
e.Graphics.DrawString(footer, printFontNormal, Brushes.Black, leftMargin, yPos);
e.Graphics.DrawRectangle(new Pen(Color.Black, 2), new Rectangle(20,600,700,500));
}
There has to be a better way. Especially when I have to change this in 6 months and have to re-figure this out.
I am using Neodynamic's thermal label SDK (http://www.neodynamic.com/ND/ProductsPage.aspx?tabid=107&prod=thermallabel) for printing to Zebra printers and am hoping for a similar API for creating a print document for a laser printer. I'll also need to add bar-code printing to this print document as well, so any tools that include bar-code functionality would be even more helpful.
Any suggestions?
If you need your windows form printed exacly as displayed on screen, I would suggest using the DrawToBitmap method. More detail: How to get a screen capture of a .Net control programmatically. This approach works also with composite controls (eg. entire form).
If you need more advanced printing features, I would suggest looking for some "reporting library" for .NET (possibly one of those: Report Viewer / Crystal Reports / SQL Server Reporting Services). Can't give any detailed guidance on this though, since I haven't used any of them myself yet.
I have a form with labels and a datagridview, and I want to print the contents. To that end, I've written the following:
int i = 0;
while(i < DataGridView1.Rows.Count)
{
e.Graphics.DrawLine(Pen, new Point(818, y), new Point(818, y + 35));
e.Graphics.DrawString(DataGridView1.Rows[i].Cells[0].Value.ToString(), new Font("Arial", 16, FontStyle.Bold), Brushes.Black, new Point(770, y + 7), format1);
y += 35;
if (y > e.PageBounds.Height - 25)
{
y = 50;
e.HasMorePages = true;
return;
}
else
{
e.HasMorePages = false;
}
i++;
}
It works when there is only one page, but subsequent pages are duplicates of the first page. When I remove the return statement, I get all the data, but on one page.
How can I fix this?