• (3 Pages)
  • +
  • 1
  • 2
  • 3

Printing in C#

#1 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1641
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Post icon  Posted 25 February 2008 - 06:26 PM

Welcome to this tutorial on Printing in C#. It used to be that printing documents in Microsoft languages was easy "back in the day". With languages such as Visual Basic it was a simple Printer.Print call. In those days, in that language, we would call that and the document would print, but since that wasn't an Object Orientated language we had no control over anything.

Fast forward many years to the magical year of 2000, the year Microsoft introduced C#. With C# there was no more Printer.Print solutions for printing your documents. Since C# is an Object Orientated language you are now able to control the entire process of printing, from the font, to the font size, to the orientation of the page (Landscape, Portrait), to the size of the print area (the page size), which of course requires some work on the programmers part. That is the purpose of this tutorial, that and the fact that Im asked at least once a day how to accomplish this task.

Since I offered a solution for the VB.Net programmers out there, I figured I'd take the time to convert that code to C# and write a tutorial for C# programmers. Since C# is more strict than VB.Net there are some changes between this class and it's VB.Net counterpart.

In this tutorial we will create our own printing class, and unlike many of the samples provided by Microsoft themselves, this one actually works right. Our class will inherit from the PrintDocument Class, located in the System.Drawing.Printing Namespace. Doing it this way will give us all the functionality of the PrintDocument, while allowing us, the developers, to determine items and override the default methods it contains. So now lets jump into some code (I know thats what you're waiting for).


Creating Our Class

As with any class, before we can use any of the Classes, Events and Objects available to us in the .Net Framework we need to import the Namespaces we need. For this we need but 3, the VB.Net counterpart only required 2 because VB.Net assumes the System Namespace, whereas C# isn't so kind:These 3 Namespaces contain everything we need for this class, so you will need to add the following lines to the top of your class file:


using System;
using System.Drawing;
using System.Drawing.Printing;




Now for the inheriting of the PrintDocument Class. To inherit from a class you need to tell your class you're inheriting from something, in our case it is the PrintDocument Class, to do this, make the following change to the declaration of your class:


public class PCPrint : System.Drawing.Printing.PrintDocument
{

}




So now we have a shell to work with that inherits from the PrintDocument Class, so lets add some functionality and other code to our class. In our class we will have 2 properties, one to hold the text that we are printing, and one to hold the Font we will be using when printing our document.

Adding the Font property allows us to override the default font. As with all properties, we need private modifiers for them, these are just private variables that will represent the values of our Properties. We make them private because we don't want their values to be changed directly. These will then be used for setting the value of our properties. First the variables:


#region  Property Variables 
/// <summary>
/// Property variable for the Font the user wishes to use
/// </summary>
/// <remarks></remarks>
private Font _font;

/// <summary>
/// Property variable for the text to be printed
/// </summary>
/// <remarks></remarks>
private string _text;
#endregion




NOTE: You will notice all the code I offer in this tutorial is separated into sections using the #region blocks. This makes for faster finding of code, especially if you have a large code file.

Now for the properties, our properties are Read/Write properties so they have both a get and set modifier. get allows us to retrieve the value of our property, while set allows us to set the property's value:


#region  Class Properties 
/// <summary>
/// Property to hold the text that is to be printed
/// </summary>
/// <value></value>
/// <returns>A string</returns>
/// <remarks></remarks>
public string TextToPrint
{
    get { return _text; }
    set { _text = value; }
}

/// <summary>
/// Property to hold the font the users wishes to use
/// </summary>
/// <value></value>
/// <returns></returns>
/// <remarks></remarks>
public Font PrinterFont
{
    // Allows the user to override the default font
    get { return _font; }
    set { _font = value; }
}
#endregion



One main difference between this class and it's VB.Net counterpart is in VB.Net you can declare a static variable inside a method, C# will scream and kick if you try this, so we must declare our variable outside any method:


#region Static Local Variables
/// <summary>
/// Static variable to hold the current character
/// we're currently dealing with.
/// </summary>
static int curChar;
#endregion





Next we will incorporate some Constructors for our class. If you dont add Constructors, the CLR assumes an empty Constructor, this allows you to instantiate your class so you can use it. We will add both an empty Constructor, and one that accepts a parameter, the parameter will be the text we want to print.

Since we are inheriting from a separate class, we need to call the Constructor of the base class. This is done by using base(), this will call the Constructor of our base class, the PrintDocument Class:


#region  Class Constructors 
/// <summary>
/// Empty constructor
/// </summary>
/// <remarks></remarks>
public PCPrint() : base()
{
    //Set the file stream
    //Instantiate out Text property to an empty string
    _text = string.Empty;
}

/// <summary>
/// Constructor to initialize our printing object
/// and the text it's supposed to be printing
/// </summary>
/// <param name=str>Text that will be printed</param>
/// <remarks></remarks>
public PCPrint(string str) : base()
{
    //Set the file stream
    //Set our Text property value
    _text = str;
}
#endregion




Now we have our Properties and our Constructors, next we will add a couple methods to our class. In our printing class we will be overriding 2 of the PrintDocument Methods, those will be the onbeginPrint Method and the onbeginPring Method. In the onbeginPrint Method we will override the default font with the font we specify, and in the OnPrintPage we will be setting up the specifics of our page. We will be setting the following properties:
  • Page Size
  • Page Orientation (Landscape, Portrait)
  • Top Margin
  • Left Margin
First, the onbeginPrint method, as with our Constructors we will need to call our base class's onbeginPrint method, then we can do our custom work:


#region  onbeginPrint 
/// <summary>
/// Override the default onbeginPrint method of the PrintDocument Object
/// </summary>
/// <param name=e></param>
/// <remarks></remarks>
protected override void onbeginPrint(System.Drawing.Printing.PrintEventArgs e)
{
    // Run base code
    base.onbeginPrint(e);

    //Check to see if the user provided a font
    //if they didn't then we default to Times New Roman
    if (_font == null)
    {
        //Create the font we need
        _font = new Font("Times New Roman", 10);
    }
}
#endregion




As you can see, here we call the base classes onbeginPrint Method, then we check to see if a font was provided, if one wasnt we default to Times New Roman. The OnPrintPage Method is quite a bit larger and complex, this is where we will be doing the bulk of our work.

In this method we will be setting the size of the print area (the page size), we will determine if the user selected Landscape or Portrait as the print style, we will determine how many lines we are printing and how many lines will fit in our page size, and finally we will tell the printer whether we have more pages to print. As with our onbeginPrint Method, we will need to call our base class's OnPrintPage Method before doing our customizing of the method. Lets take a look at our overridden OnPrintPage Method:


#region  OnPrintPage 
/// <summary>
/// Override the default OnPrintPage method of the PrintDocument
/// </summary>
/// <param name=e></param>
/// <remarks>This provides the print logic for our document</remarks>
protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e)
{
    // Run base code
    base.OnPrintPage(e);

    //Declare local variables needed
    
    int printHeight;
    int printWidth;
    int leftMargin;
    int rightMargin;
    Int32 lines;
    Int32 chars;

    //Set print area size and margins
    {
        printHeight = base.DefaultPageSettings.PaperSize.Height - base.DefaultPageSettings.Margins.Top - base.DefaultPageSettings.Margins.Bottom;
        printWidth = base.DefaultPageSettings.PaperSize.Width - base.DefaultPageSettings.Margins.Left - base.DefaultPageSettings.Margins.Right;
        leftMargin = base.DefaultPageSettings.Margins.Left;  //X
        rightMargin = base.DefaultPageSettings.Margins.Top;  //Y
    }

    //Check if the user selected to print in Landscape mode
    //if they did then we need to swap height/width parameters
    if (base.DefaultPageSettings.Landscape)
    {
        int tmp;
        tmp = printHeight;
        printHeight = printWidth;
        printWidth = tmp;
    }

    //Now we need to determine the total number of lines
    //we're going to be printing
    Int32 numLines = (int)printHeight / PrinterFont.Height;

    //Create a rectangle printing are for our document
    RectangleF printArea = new RectangleF(leftMargin, rightMargin, printWidth, printHeight);

    //Use the StringFormat class for the text layout of our document
    StringFormat format = new StringFormat(StringFormatFlags.LineLimit);

    //Fit as many characters as we can into the print area      

    e.Graphics.MeasureString(_text.Substring(RemoveZeros(curChar)), PrinterFont, new SizeF(printWidth, printHeight), format, out chars, out lines);

    //Print the page
    e.Graphics.DrawString(_text.Substring(RemoveZeros(curChar)), PrinterFont, Brushes.Black, printArea, format);

    //Increase current char count
    curChar += chars;

    //Detemine if there is more text to print, if
    //there is the tell the printer there is more coming
    if (curChar < _text.Length)
    {
        e.HasMorePages = true;
    }
    else
    {
        e.HasMorePages = false;
        curChar = 0;
    }
}

#endregion




You will notice that in this method we reference a function called RemoveZeros. This is the last function in our class, and it has an important role. Instead of using ugly nested if..else statements, we will create a function that will check our value, and if it's a 0 (zero) we will replace it with a 1 (one). Zero's can cause bad things to happen when it comes to printing and determining page size and margins, so to alleviate that we use our RemoveZeros Function:


#region  RemoveZeros 
/// <summary>
/// Function to replace any zeros in the size to a 1
/// Zero's will mess up the printing area
/// </summary>
/// <param name=value>Value to check</param>
/// <returns></returns>
/// <remarks></remarks>
public int RemoveZeros(int value)
{
    //Check the value passed into the function,
    //if the value is a 0 (zero) then return a 1,
    //otherwise return the value passed in
    switch (value)
    {
        case 0:
            return 1;
        default:
            return value;
    }
}
#endregion




And there you have it, our completed printing class. Now I know some are asking "I see this class, but how do I use it?". Well I'm glad you asked, this class is much easier to use than one would imagine. In your Form's code I would create a procedure, lets name it printDocument, then inside that procedure we would create an instance of our printer class, set its properties (PrinterFont, TextToPrint), then issue a print command, like this:


#region  PrintDocument 
public void PrintDocument()
{
	//Create an instance of our printer class
	PCPrint printer = new PCPrint();
	//Set the font we want to use
	printer.PrinterFont = new Font("Verdana", 10);
	//Set the TextToPrint property
	printer.TextToPrint = Textbox1.Text;
	//Issue print command
	printer.Print();
}
#endregion




Then in the click event of your print button call PrintDocument, and your document will print. Thats it, thats how easy it is to use your new printer class. This class is reusable, you can incorporate it anywhere you have documents that need to be printed. If you wanted to print graphics some functionality would need to be added, those changes will be in a completely separate tutorial.

I hope you found this tutorial on Printing in C# to be useful and informative, and I thank you for reading. I will be including the class used in this tutorial, but remember it is under the GPL - General Public License. With this license you can modify this code to suite your needs, but the license header must remain in tact. :)

Happy Coding!

Attached File  PC_Printer_CSharp.zip (13.48K)
Number of downloads: 24344

This post has been edited by PsychoCoder: 26 February 2008 - 02:55 AM


Is This A Good Question/Topic? 1
  • +

Replies To: Printing in C#

#2 Nayana  Icon User is offline

  • DIC Hawk - 나야나 नयन:
  • member icon

Reputation: 31
  • View blog
  • Posts: 824
  • Joined: 14-November 07

Posted 26 February 2008 - 02:21 AM

View PostPsychoCoder, on 26 Feb, 2008 - 09:26 AM, said:

I hope you found this tutorial on Printing in VB.Net...


Your tutorial is 0.00014% wrong (based on character count).

:)


Thanks for it btw. I once knew how to print in C#, but I haven't done it in a couple of years, and this is saving me having to re-research it.
Was This Post Helpful? 0
  • +
  • -

#3 ScottBrady  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 28-January 08

Posted 01 March 2008 - 06:04 AM

Hi this is a great tutorial. Thanks.

My only question is related to the GPL. I am a little confused on its implications.

By using this class in any program I write does this mean that I also have make my program taken as a whole under the GPL and if so does this prevent me from selling my program as a commercial product.

Kind Regards

ScottBrady
Was This Post Helpful? 0
  • +
  • -

#4 ScottBrady  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 28-January 08

Posted 22 March 2008 - 02:40 PM

Hi All,

I have asked around in a number of other online forums and it appears that you can use GPL code in commercial applications as long as you do not include the source code with your own.

Instead you can link to a dll of the GPL'd code. You still need to adhere to the liscence of the GPL by making the source code of the GPL portion available.

Hope this helps anybody else asking the same question.

Regards

ScottBrady
Was This Post Helpful? 0
  • +
  • -

#5 jaredharley  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 7
  • Joined: 18-August 08

Posted 18 August 2008 - 02:39 AM

I am using the same code as you for the print class, save a different font. I call the print class from my form and send through a concatenated string of text (basically spacing out the information with new lines), and everything works great, except for one problem - I am always getting a second page, and the information is no more than half a page long. This is the code that calls the print class:

// Call the printer class and print
PrintRecord.PCPrint printer = new PrintRecord.PCPrint();
printer.PrinterFont = new Font("Arial", 12);
printer.TextToPrint = printString;
printer.PrinterSettings.PrinterName = printerName;
printer.PrinterSettings.Copies = numberCopies;
printer.DocumentName = firstNameText.Text + " " + lastNameText.Text;
printer.PrinterSettings.MaximumPage = 1;
printer.PrinterSettings.ToPage = 1;
printer.Print();


You can see I tried to control the page length to a single page, but with no luck. I can't find any reason I should be getting a second page - any idea what might be causing it? Thanks for the great walkthrough!
Was This Post Helpful? 0
  • +
  • -

#6 jaredharley  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 7
  • Joined: 18-August 08

Posted 18 August 2008 - 11:29 AM

After some testing, I discovered what seems to have been the issue.

The problem was in the if/else statement that determined if there were any more pages to send to the printer - in my project, curChar was ending up equal to _text.Length, so the code sent an additional page. I stopped this by modifying the code as below:

if (curChar + 1 < _text.Length)
{
	e.HasMorePages = true;
}
else
{
	e.HasMorePages = false;
	curChar = 0;
}

Was This Post Helpful? 0
  • +
  • -

#7 smallet  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 30-September 08

Posted 30 September 2008 - 11:07 AM

Hi !

I was wondering how could I modify the code so that it shows the print dialog box and then print, using the same class structure.

So far I have

#region  PrintDocument
		public void PrintDocument(string toBePrinted)
		{
			//Create an instance of our printer class
			PCPrint printer = new PCPrint();
			//Set the font we want to use
			printer.PrinterFont = new Font("Verdana", 10);
			//Set the TextToPrint property
			printer.TextToPrint = " " + toBePrinted;
			if (Program.frmMainApp.hashSettings["USE_PRINTER"].ToString() == "default")
			{
				//Issue print command
				printer.Print();
			}
			else
			{
				PrintDialog pdlg = new PrintDialog();

				if (pdlg.ShowDialog() == DialogResult.OK)
				{
					try
					{
						pdlg.Document = printer;
						printer.Print();
					}
					catch (Exception ex)
					{
						MessageBox.Show("Print error: " + ex.Message);
					}
				}
			}
		}
		#endregion



But whatever I do, it still prints to the default printer...

This post has been edited by smallet: 30 September 2008 - 11:10 AM

Was This Post Helpful? 0
  • +
  • -

#8 ChaosCode  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 2
  • Joined: 11-January 09

Posted 11 January 2009 - 06:42 AM

Thanks, great code.

Mine is working fine, except it does not print the first caracter of the first line.

Can't find the problem
Anyone knows where to look?
Was This Post Helpful? 0
  • +
  • -

#9 pdy123  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 03-March 09

Posted 03 March 2009 - 06:08 PM

thank you for your information ,but I still have no idea to solve my problem .I want to print local form which have some other controls .my code only print local form's height ,while not print rolling form that are Invisible.it's means printing not completely.such as my code...


private void CaptureScreen(Control ctrl)
{
Graphics mygraphics = ctrl.CreateGraphics();
Size sTmp = ctrl.Size;

memoryImage = new Bitmap(sTmp.Width, sTmp.Height, mygraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
IntPtr ipSource = mygraphics.GetHdc();
IntPtr ipTarget = memoryGraphics.GetHdc();

BitBlt(ipTarget, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, ipSource, 0, 0, 13369376);
//BitBlt(ipTarget, 0, 0, ctrl.Width, ctrl.Height, ipSource, 0, 0, 13369376);

mygraphics.ReleaseHdc(ipSource);
memoryGraphics.ReleaseHdc(ipTarget);
Graphics mygraphics = ctrl.CreateGraphics();
Was This Post Helpful? 0
  • +
  • -

#10 sonet  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 02-June 09

Posted 02 June 2009 - 04:17 PM

View Postsmallet, on 30 Sep, 2008 - 10:07 AM, said:

I was wondering how could I modify the code so that it shows the print dialog box and then print, using the same class structure.

But whatever I do, it still prints to the default printer...




You can retrieve the printer name in the following way:


			PrintDialog pd = new PrintDialog();
			PrinterSettings ps = new PrinterSettings();
			pd.PrinterSettings = ps;
			DialogResult dr = pd.ShowDialog();

			if (dr == DialogResult.OK)
			{
				printer.PrinterSettings.PrinterName = pd.PrinterSettings.PrinterName;
				printer.PrinterFont = new Font("Verdana", 10);
				printer.TextToPrint = "Test Print";
				printer.Print();
			}





Regards

Sonet
Was This Post Helpful? 0
  • +
  • -

#11 D.Ginzbourg  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 03-July 09

Posted 03 July 2009 - 03:36 AM

View PostPsychoCoder, on 25 Feb, 2008 - 05:26 PM, said:

Welcome to this tutorial on Printing in C#. It used to be that printing documents in Microsoft languages was easy "back in the day". With languages such as Visual Basic it
.
.
.
.
.
.


I wrote and added everything you said, now after i did it, it says:
Error 1 The name 'TextBox1' does not exist in the current context C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs 332 39 WindowsFormsApplication1

I'm kinda new in Windows Applications, so ill post the whole code, and tell you the properties of the program i wanted to make.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Drawing.Printing;
using System.Windows.Forms;



namespace WindowsFormsApplication1
{
	public partial class Form1 : Form
	{

		public Form1()
		{


			InitializeComponent();
		}

		int bank = 1;
		private void btnCalc_Click(object sender, EventArgs e)
		{

			int num = 3;
			int cablegp = 0, end = 0; //  cablegp is numbers of cables in group (input)
			double lengGP = 0, bank2 = 0, bankMin = 0, bankPlus = 0, bank3 = 0; //  lengGP is the length of the group (input) 
		   



			for (; end == 0; )
			{



				cablegp = int.Parse(textBox1.Text);
				lengGP = int.Parse(textBox2.Text);
				bank2 = Math.Round((lengGP * 0.67), 1);
				bankMin = (bank2 - 0.1);
				bankPlus = (bank2 + 0.1);
				bank3 = Math.Round(lengGP, 1);

				for (int i = 0; i < cablegp; i++, bank++)
				{

					num *= 3;
					textBox3.Text += "----------" + bank.ToString();
					textBox3.Text += "						  " + bank3.ToString() + "						 ";

					//CONDITION PART==============================================================================

					if ((num % 10) == 0)
					{
						textBox3.Text += bankPlus.ToString() + "			 ";
					}
					else if ((num % 10) == 1)
					{
						textBox3.Text += bankPlus.ToString() + "			 ";
					}
					else if ((num % 10) == 2)
					{
						textBox3.Text += bank2.ToString() + "			 ";
					}
					else if ((num % 10) == 3)
					{
						textBox3.Text += bankMin.ToString() + "					";
					}
					else if ((num % 10) == 4)
					{
						textBox3.Text += bankPlus.ToString() + "					";
					}
					else if ((num % 10) == 5)
					{
						textBox3.Text += bank2.ToString() + "					";
					}
					else if ((num % 10) == 6)
					{
						textBox3.Text += bankMin.ToString() + "					";
					}
					else if ((num % 10) == 7)
					{
						textBox3.Text += bankPlus.ToString() + "					";
					}
					else if ((num % 10) == 8)
					{
						textBox3.Text += bank2.ToString() + "					";
					}
					else if ((num % 10) == 9)
					{
						textBox3.Text += bankMin.ToString() + "					";
					}
					else
					{
						textBox3.Text += bank2.ToString() + "					";
					}

					//CONDITION PART==============================================================================


				}

				MessageBox.Show("Group Done.  To Continue Press 'OK' and enter two more numbers. ",
						"END",
						MessageBoxButtons.OK,
						MessageBoxIcon.Information);
				end = 1;
			   
			}
			


		}
		//PRINTCONTROL=======================================================================================================

		public class PCPrint : System.Drawing.Printing.PrintDocument
		{
			#region  Property Variables 
			/// <summary>
			/// Property variable for the Font the user wishes to use
			/// </summary>
			/// <remarks></remarks>
			private Font _font;

			/// <summary>
			/// Property variable for the text to be printed
			/// </summary>
			/// <remarks></remarks>
			private string _text;
			#endregion

			#region  Class Properties 
			/// <summary>
			/// Property to hold the text that is to be printed
			/// </summary>
			/// <value></value>
			/// <returns>A string</returns>
			/// <remarks></remarks>
			public string TextToPrint
			{
			get { return _text; }
			set { _text = value; }
			}
			
			/// <summary>
			/// Property to hold the font the users wishes to use
			/// </summary>
			/// <value></value>
			/// <returns></returns>
			/// <remarks></remarks>
			public Font PrinterFont
			{
			// Allows the user to override the default font
			get { return _font; }
			set { _font = value; }
			}
			#endregion


			#region Static Local Variables
			/// <summary>
			/// Static variable to hold the current character
			/// we're currently dealing with.
			/// </summary>
			static int curChar;
			#endregion


			#region  Class Constructors
			/// <summary>
			/// Empty constructor
			/// </summary>
			/// <remarks></remarks>
			public PCPrint()
				: base()
			{
				//Set the file stream
				//Instantiate out Text property to an empty string
				_text = string.Empty;
			}

			/// <summary>
			/// Constructor to initialize our printing object
			/// and the text it's supposed to be printing
			/// </summary>
			/// <param name=str>Text that will be printed</param>
			/// <remarks></remarks>
			public PCPrint(string str)
				: base()
			{
				//Set the file stream
				//Set our Text property value
				_text = str;
			}
			#endregion


			#region  onbeginPrint;
			/// <summary>
			/// Override the default onbeginPrint method of the PrintDocument Object
			/// </summary>
			/// <param name=e></param>
			/// <remarks></remarks>
			protected override void onbeginPrint(System.Drawing.Printing.PrintEventArgs e)
			{
			// Run base code
			base.onbeginPrint(e);
		
			//Check to see if the user provided a font
			//if they didn't then we default to Times New Roman
			if (_font == null)
			{
			 //Create the font we need
			_font = new Font("Times New Roman", 10);
			}
			}
			#endregion



			#region  OnPrintPage
			/// <summary>
			/// Override the default OnPrintPage method of the PrintDocument
			/// </summary>
			/// <param name=e></param>
			/// <remarks>This provides the print logic for our document</remarks>
			protected override void OnPrintPage(System.Drawing.Printing.PrintPageEventArgs e)
			{
				// Run base code
				base.OnPrintPage(e);

				//Declare local variables needed

				int printHeight;
				int printWidth;
				int leftMargin;
				int rightMargin;
				Int32 lines;
				Int32 chars;

				//Set print area size and margins
				{
					printHeight = base.DefaultPageSettings.PaperSize.Height - base.DefaultPageSettings.Margins.Top - base.DefaultPageSettings.Margins.Bottom;
					printWidth = base.DefaultPageSettings.PaperSize.Width - base.DefaultPageSettings.Margins.Left - base.DefaultPageSettings.Margins.Right;
					leftMargin = base.DefaultPageSettings.Margins.Left;  //X
					rightMargin = base.DefaultPageSettings.Margins.Top;  //Y
				}

				//Check if the user selected to print in Landscape mode
				//if they did then we need to swap height/width parameters
				if (base.DefaultPageSettings.Landscape)
				{
					int tmp;
					tmp = printHeight;
					printHeight = printWidth;
					printWidth = tmp;
				}

				//Now we need to determine the total number of lines
				//we're going to be printing
				Int32 numLines = (int)printHeight / PrinterFont.Height;

				//Create a rectangle printing are for our document
				RectangleF printArea = new RectangleF(leftMargin, rightMargin, printWidth, printHeight);

				//Use the StringFormat class for the text layout of our document
				StringFormat format = new StringFormat(StringFormatFlags.LineLimit);

				//Fit as many characters as we can into the print area	  

				e.Graphics.MeasureString(_text.Substring(RemoveZeros(curChar)), PrinterFont, new SizeF(printWidth, printHeight), format, out chars, out lines);

				//Print the page
				e.Graphics.DrawString(_text.Substring(RemoveZeros(curChar)), PrinterFont, Brushes.Black, printArea, format);

				//Increase current char count
				curChar += chars;

				//Detemine if there is more text to print, if
				//there is the tell the printer there is more coming
				if (curChar < _text.Length)
				{
					e.HasMorePages = true;
				}
				else
				{
					e.HasMorePages = false;
					curChar = 0;
				}
			}

			#endregion


			#region  RemoveZeros
			/// <summary>
			/// Function to replace any zeros in the size to a 1
			/// Zero's will mess up the printing area
			/// </summary>
			/// <param name=value>Value to check</param>
			/// <returns></returns>
			/// <remarks></remarks>
			public int RemoveZeros(int value)
			{
				//Check the value passed into the function,
				//if the value is a 0 (zero) then return a 1,
				//otherwise return the value passed in
				switch (value)
				{
					case 0:
						return 1;
					default:
						return value;
				}
			}
			#endregion



			#region  PrintDocument
			public void PrintDocument()
			{
				//Create an instance of our printer class
				PCPrint printer = new PCPrint();
				//Set the font we want to use
				printer.PrinterFont = new Font("Verdana", 10);
				//Set the TextToPrint property
				printer.TextToPrint = TextBox1.Text;
				//Issue print command
				printer.Print();
			}
			#endregion






		}

		//PRINTCONTROL=============================================================================================================



		private void Form1_Load(object sender, EventArgs e)
		{

		}
	}
}




You write in textBox1 how many cables you have, in textBox2 you write whats the length of those cables. You press on btnCalc and it writes in textBox3 a table (table made of spaces, not real table). Now i want it to print the table i made in the same form (so it will remain a table when print). I tried to put textBox3.Text instead of TextBox1.Text, but it says:

Error 1 Cannot access a non-static member of outer type 'WindowsFormsApplication1.Form1' via nested type 'WindowsFormsApplication1.Form1.PCPrint' C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\WindowsFormsApplication1\WindowsFormsApplication1\Form1.cs 332 39 WindowsFormsApplication1

Thanks for all helpers in advance.

I will attack Form Design Code just incase someone needs it.

Attached File(s)


Was This Post Helpful? 0
  • +
  • -

#12 Cryatal  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 9
  • Joined: 21-November 09

Posted 22 November 2009 - 03:31 PM

View PostPsychoCoder, on 25 Feb, 2008 - 05:26 PM, said:

Now we have our Properties and our Constructors, next we will add a couple methods to our class. In our printing class we will be overriding 2 of the PrintDocument Methods, those will be the onbeginPrint Method and the onbeginPring Method. In the onbeginPrint Method we will override the default font with the font we specify, and in the OnPrintPage we will be setting up the specifics of our page. We will be setting the following


Great tutorial, just what I needed for my college project :)

minor error though when explaining the methods. Might want to change onbeginPring* to OnPrintPage.

Thanks for the help :)

This post has been edited by Cryatal: 22 November 2009 - 03:33 PM

Was This Post Helpful? 0
  • +
  • -

#13 jkoehling  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 06-January 10

Posted 06 January 2010 - 10:45 AM

I might be doing something stoopid, but I cannot seem to open your ZIP file. My attempts to extract the files result in a an error message: "The Compressed (zipped) Folder is invalid or corrupted". May I implore you for any advice? Thanks in advance!
Was This Post Helpful? 0
  • +
  • -

#14 matrix0009  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 27-February 10

Posted 02 March 2010 - 02:04 AM

Hello everyone.


Hi PsychoCoder,
I am using Windows Forms in Visual Studio 2008 C# and I've included your code on my program but I get some errors.

I added The PCPrint.cs on my project. and add the ff. code on the form that I am working with.

public void PrintDocument()
{
//Create an instance of our printer class
PCPrint printer = new PCPrint();
//Set the font we want to use
printer.PrinterFont = new Font("Verdana", 10);
//Set the TextToPrint property
printer.TextToPrint = Textbox1.Text;
//Issue print command
printer.Print();
}

private void button1_Click(object sender, EventArgs e)
{
PrintDocument();
}


When I tried to debug my program, the errors were:

1 The type or namespace name 'PCPrint could not be found (are you issing a using directive or an assembly reference?)'

2 The type or namespace name 'PCPrint could not be found (are you issing a using directive or an assembly reference?)'

3 The name 'Textbox1' does not exist in the current context

**the 1st two errors were pointing to:
PCPrint printer = new PCPrint();

What could be the problem here?
I looked at the references on my project, there is no 'System.Drawing.Printing'. I tried to add it but i can't find it when i add references.

Hi! I am using Windows Forms in Visual Studio 2008 C# and I've included your code on my program but I get some errors.

I added The PCPrint.cs on my project. and add the ff. code on the form that I am working with.
       public void PrintDocument()
        {
            //Create an instance of our printer class
            PCPrint printer = new PCPrint();
            //Set the font we want to use
            printer.PrinterFont = new Font("Verdana", 10);
            //Set the TextToPrint property
            printer.TextToPrint = Textbox1.Text;
            //Issue print command
            printer.Print();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            PrintDocument();
        }



When I tried to debug my program, the errors were:

1 The type or namespace name 'PCPrint could not be found (are you issing a using directive or an assembly reference?)'

2 The type or namespace name 'PCPrint could not be found (are you issing a using directive or an assembly reference?)'

3 The name 'Textbox1' does not exist in the current context

**the 1st two errors were pointing to:
PCPrint printer = new PCPrint();

What could be the problem here?
I looked at the references on my project, there is no System.Drawing.Printing. I tried to add it but i can't find it when i add references.
Was This Post Helpful? 0
  • +
  • -

#15 Guest_Duncan*


Reputation:

Posted 17 March 2010 - 05:07 AM

Hi all

Great article, works great apart from the missing character at the start of the letter and adding the extra page with the last character of the letter on.

But don't don't worry I fixed them.

Using the original code replace the following...

In the OnPrintPage method you will need to add ref's for the curChar...

e.Graphics.MeasureString(_text.Substring(RemoveZeros(ref curChar)), PrinterFont, new SizeF(printWidth, printHeight), format, out chars, out lines);

e.Graphics.DrawString(_text.Substring(RemoveZeros(ref curChar)), PrinterFont, Brushes.Black, printArea, format);



...this will allow the RemoveZeros method to keep the curChar in the correct index and stopping the extra page.

Next replace the RemoveZeros method with the following...

public int RemoveZeros(ref int value)
{
    //As 0 (ZERO) being sent to DrawString will create unexpected
    //problems when printing we need to search for the first
    //non-zero character in the string.
    while (_text[value] == '\0')
    {
        value++;
    }
    return value;
}



...everytime you start using the DrawString you need to check there are no 0's (ZERO's) at the start of the string otherwise you'll get unexpected results. I've extended this method so it will check the start of the string and also do it on the next page to print which the previous version didn't do.

Enjoy.

Duncan
Was This Post Helpful? 0

  • (3 Pages)
  • +
  • 1
  • 2
  • 3