Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / Visual Basic

Windows Form Screenshot and Print Preview in VB.NET

Rate me:
Please Sign up or sign in to vote.
5.00/5 (10 votes)
12 Mar 2012CPOL8 min read 111.2K   2.4K   17   27
How to take a screenshot of a Windows form and then print it.

Introduction

This article talks about how to take a screenshot of a Windows form and then print it.

As I am working on an application, I end up with several smaller test applications to learn about different ways to do something. After creating them, they are a great source to go back to if I don’t have to do a certain thing for a while so I can remember how to do it. Always comment code well.

In my current main project, it inputs 4 dimensions and 2 options, does over 100 calculations and then outputs 8 final dimensions.

I wanted to print the form and output for the end user, and since I’ve haven’t worked much with printing, or screenshots, I had a lot to learn.

I wasn’t sure how to print a form so I added all of the standard controls and looked to see what it would do for me. That didn’t turn out very well, you can’t just add the controls and hope to fumble your way through to get it to work. So I downloaded and installed the Visual Basic Power pack 3. After some reading, trial, and a lot of error, I decided I didn’t want to use the Power pack because it had to be installed on the end user system in order for the printing to work. So I went back to the internet, and started by searching for how to take a screenshot. I found an interesting C# version that took a screenshot of the entire screen then saved it to a file (located here). After converting it to VB.NET, I was ready to see what it could do.

It worked great for taking a screen of the entire screen, but I wanted just the form.

C# and Converted VB.NET Code

C#
//C#
private void btnCapture_Click(object sender, EventArgs e)
{
    Graphics graph = null;
    try
    {
        Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
                                Screen.PrimaryScreen.Bounds.Height);
        graph = Graphics.FromImage(bmp);
        graph.CopyFromScreen(0,0, 0, 0, bmp.Size);
        SaveImage(bmp);
    }
    finally
    {

'VB.NET

Private Sub btnCapture_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnCapture.Click
    Dim graph As Graphics = Nothing
    Try
        Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
        graph = Graphics.FromImage(bmp)
        graph.CopyFromScreen(0,0, 0, 0, bmp.Size
        SaveImage(bmp)
    Catch ex As Exception
    End Try
End Sub

(Note: The C# code errored out when trying to use an online code converter.)

Now that I had working code to create the screenshot with, it was time to start tweaking the code to get it to just take a screenshot of just the form.

Rather than taking the screenshot, then finding and opening up the image each time I saved the file, I added the ability for Microsoft Paint to open and view the image after each screenshot was taken, it will overwrite the file each time so only 1 file is left, unless you add code to delete the file. After the screenshot was saved, I could go back and change the numbers for the size, and location of what was captured. After getting the result you want, you can just comment out the code or remove it all together.

(Note 2: The screenshot is saved to the debug or release folder that the program is run from, using the code above “SaveImage(bmp)”. I had to change the output to the “c:\Filename.png” because it would not find the file with the number of characters it took for the path length to where the projects were saved, and starting Microsoft Paint from code to open the file.)

ScreenCaptureSavedandOpenedInPaint

Final Code for Screen Capture Test

VB.NET
Private Sub GetScreenshot_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles GetScreenshot.Click
    Dim graph As Graphics = Nothing Try
    ' gets the upper left hand coordinate of the form
    Dim frmleft As System.Drawing.Point = Me.Bounds.Location

    'use the commented out version for the full screen
    'Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, _Screen.PrimaryScreen.Bounds.Height)
    'this version get the size of the form1
    'The + 8 adds a little to right and bottom of what is captured.
    Dim bmp As New Bitmap(Me.Bounds.Width + 8, Me.Bounds.Height + 8)

    'creates the grapgic
    graph = Graphics.FromImage(bmp)

    'Gets the x,y coordinates from the upper left start point
    'used below Dim screenx As Integer = frmleft.X
    Dim screeny As Integer = frmleft.Y

    ' The - 5 here allows more of the form to be shown for the top and left sides.
    graph.CopyFromScreen(screenx - 5, screeny - 5, 0, 0, bmp.Size)

    ' Save the Screenshot to a file
    bmp.Save("C:\temp.png")

    'Open File and load in MS Paint Dim filepath As String
    filepath = "C:\temp.png"
    Process.Start("mspaint.exe ", filepath)

    bmp.Dispose()
    graph.Dispose()
Catch ex As Exception
    MsgBox(ex.Message)
End Try End Sub

The code above is just the button click event to get the capture and then start Microsoft Paint with the saved screenshot.

As you can see from all of the comments, we first set the variable graph = to nothing.

Next, we want to get the location of the upper left hand corner of the form. We then set the variable bmp as a new Bitmap type and get the size of what we want to capture. I added 8 to the width and height to get more of the right and bottom of the border to display. It may be different for different border types.

We set the variable graph = to a graphics object created from the image bmp. Next we get the X,Y coordinates of the upper left hand corner of our form from the “frmleft” variable we got first.

We then do “graph.CopyFromScreen(screenx – 5, screeny – 5, 0, 0, bmp.Size)”. Here I subtracted 5 from each of the input X,Y coordinated to capture more of the left and top of the form.

This saves the image to the variable starting at the input X,Y and the output X,Y and then Width and height of the capture represented as the variable “bmp.Size” .The output X, Y coordinates will almost always be “0” Zero.

Next, we save the file to the local system so Microsoft Paint can open it for viewing the result. As of this writing, I have not tested for ways of bypassing saving the file to disk yet. We then open the file for viewing with Microsoft Paint. Finally we Dispose, or release the graphic objects.

The next trick is to figure out how to output this to a printer.

After several hours and many failed attempts trying any code I could find, I finally discovered that text and images are handled a little differently.

Final Code for Outputting to a Print Preview Control

VB.NET
Private Sub btnPrintPreview_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnPrintPreview.Click

    PrintPreviewDialog1.ShowDialog()

End Sub

Public Sub New()
    MyBase.New()
    InitializeComponent()
End Sub

Private Sub Print_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load
    ' The example assumes your form has a Button control,
    ' a PrintDocument component named myDocument,
    ' and a PrintPreviewDialog control.
    ' Handle the PrintPage event to write the print logic.
    AddHandler PrintDocument2.PrintPage, AddressOf Me.printDocument2_PrintPage

    ' Specify a PrintDocument instance for the PrintPreviewDialog component.
     Me.PrintPreviewDialog1.Document = Me.PrintDocument2
End Sub

Private Sub printDocument2_PrintPage(ByVal sender As Object, _
            ByVal e As System.Drawing.Printing.PrintPageEventArgs)
    ' Specify what to print and how to print in this event handler.
    ' This gives us the left X, and the top Y location of the printable area
    ' plus how much we want something to pad to the right or from the top of the Printable Area
    'If the number was equal the printable area it may not print. 
    Dim prnborderX As Single
    prnborderX = PrintDocument2.DefaultPageSettings.PrintableArea.X + 1 
    Dim prnborderY As Single
    prnborderY = PrintDocument2.DefaultPageSettings.PrintableArea.Y + 10
    'This is the Width and height of the printable area. As a Single. 
    Dim pagewidth As Single
    pagewidth = PrintDocument2.DefaultPageSettings.PrintableArea.Width
    Dim pageHeight As Single
    pageHeight = PrintDocument2.DefaultPageSettings.PrintableArea.Height

    'Set the font, text color,and line color Dim f As Font = New Font("Vanada", 12)
    Dim br As SolidBrush = New SolidBrush(Color.Black)
    Dim p As Pen = New Pen(Color.Black)
    Dim g As Pen = New Pen(Color.CornflowerBlue)

    ' Get the strings for the paper size and the printable area for the output. 

    Dim PrntDoc2 As String
    PrntDoc2 = "Paper Size = " & PrintDocument2.DefaultPageSettings.PaperSize.ToString
    Dim prndoc2default
    prndoc2default = "Printable Area = " & PrintDocument2.DefaultPageSettings.PrintableArea.ToString

    e.Graphics.DrawString(PrntDoc2, f, Brushes.RosyBrown, 50, 70)
    'paint the text for paper size
    e.Graphics.DrawString(prndoc2default, f, Brushes.Black, 50, 90)
    'paint the text printable area
    e.Graphics.DrawRectangle(p, 50, 150, 300, 150)
    'paint the small box
    'paint the border box  around the printable area
    e.Graphics.DrawRectangle(g, prnborderX, prnborderY, pagewidth - 50, pageHeight - 25)

    'paint the image to the printpreview control and scale to fit.
    Dim drawImg As New Bitmap("C:\temp.png")
    Dim mgHeight As Single = drawImg.Height
    Dim mgWidth As Single = drawImg.Width
    'This part is for the scaling , gets the input size and the output 
    'size for image to scale to automaticly
    Dim sourceRectangle As New Rectangle(0, 0, mgWidth, mgHeight)
    Dim destRetangle1 As New Rectangle(40, 350, pagewidth - 75, 600)
    e.Graphics.DrawImage(drawImg, destRetangle1, sourceRectangle, GraphicsUnit.Pixel)

    'get the image size and paint the text of the sizes
    'to the print preview control 
    Dim PictureSize As String
    PictureSize = ("Image Width = " & mgWidth.ToString & _
                   "   Image Height = " & mgHeight.ToString)
    e.Graphics.DrawString(PictureSize, f, Brushes.Blue, 50, 110)

End Sub

The first thing we need to do is add a standard Print Preview Control and a Print Document control to the form. Just using these, you don’t need the power pack. (As far as I know of anyway.)

Next a Button or use a menu item for opening the Print Preview window with the click event.

Next, we add a Component initializer for the code in the Print_Load sub.

Next we need the handlers for the Print Document Control and the “Address Of “ to the sub that will do the work of what will be “Painted” to the Print Preview control.

PrintDocument2 is the name of the Print Document control that was added they need to match. printDocument2_PrintPage is the name of the sub that will do the work.

If the Component initializer and the “Print_Load” sub are not present, then the Print preview control will not display anything.

Next, we move onto the printDocument2_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs). printDocument2_PrintPage is a variable name but the rest needs to be the same.

Next, I need to understand the terms and what they are used for.

Font, the font to use, set what font name you want here. Just make sure it is common font or it may fail on other systems.

Solid Brush, solid brush will be used with text for setting the color, or filling in areas.

Pen, the pen is used for setting the color of lines or shapes.

e.Graphics.DrawString this is event driven, so this tells the DrawString event to draw the (string that is referenced, the font to use, the color of the brush to use, the X,Y coordinates to start painting the text at from the top left hand corner of the page).

This test program:

  1. Outputs an Outline Box just inside of the printable area, to help see where the printable area is as laid out on the print preview control.
  2. Prints the paper size of the default printer as a string.
  3. Prints the Printable Area of the default printer, (this may be different for each individual printer).
  4. Draws a box (left over from some test code).
  5. Then paints the image scaled to the width of the printable area. I used the printable area outline box to help me center the image by adjusting the parameters.

When this page was printed, the outline box was centered on the paper, not offset to the left like the preview shows.

Let's see what the output looks like:

PrintPreviewTest12

At this point after all that I have learned, rather than outputting a screenshot to the print preview control, I can just pass the text needed to be displayed from either the output text boxes or globally declared variables for the items I need displayed, for a more printer friendly version.

Final Notes

This test application does not have error handling for when the image file does not exist. So the screenshot button will need to be hit at least once.

This test program does not have any code for using the landscape view. But another sub form in this project has a button for opening the “print setup dialog” but no code for saving a selection of landscape or portrait.

On another sub form in this project is a button to list all of the default values for the default printer. All sub forms can be opened from a button starting from the main form.

Download

The source and binary are available from my SkyDrive folder.

Due to Microsoft Closing down their offering of Microsoft Office Live Small Business service and forcing their current customers to either move to the new Office 365 program and completely rebuild their web sites again or find a new web host and rebuild there site. Effective April 30, 2012.

After that, my website may be gone or moved to a new host. I also may not be able to keep the SkyDrive location my articles refer to after that since it is tied to my website.

Conclusion

After all that I have learned over that last few days, once you learn what is required to do the job, it is not difficult to implement the screen shot or the printing. I see no need at the moment to use a third party control that may require it to be installed, and possibly break you application because of it. Just some number changes can move your image or text anywhere you want. A person could even make a few snippets with the replacements set for quicker use later.

I hope someone learned as much from this adventure as I did.

Links

MSDN Sites

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO PC's Xcetra
United States United States
My first experience with computers was when my mom gave a Timex Sinclair 1000 to me for Christmas some time in the late 70's (I still have it)There I learned to copy code from magazines to save to cassette tapes for playing games.

Since then I have dabbled in:
Basic,Qbasic,ruby,python,Java Script, HTML, CSS, C#, C++, Perl, and a few other I can't think of off hand.
Now I Mainly work with VB Script and VB.Net
I Prefer to build programs that make use of the GUI so I don't have to remember all of the syntax for console apps. I realy don't care much for HTML because of the way you build and then run to see if it looks right. Also the new WPF is to much like HTML so I steer clear of it for now.
Most of what I build is for getting information from a system to use in system repair.I make heavy use of the WMI classes. Why reinvent something.

Comments and Discussions

 
Questiongetting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
Member 1264953127-Jul-16 20:12
Member 1264953127-Jul-16 20:12 
QuestionRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
ledtech327-Jul-16 20:54
ledtech327-Jul-16 20:54 
AnswerRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
Member 1264953129-Jul-16 1:54
Member 1264953129-Jul-16 1:54 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
ledtech329-Jul-16 4:55
ledtech329-Jul-16 4:55 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
Member 1264953131-Jul-16 18:25
Member 1264953131-Jul-16 18:25 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
ledtech331-Jul-16 19:46
ledtech331-Jul-16 19:46 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
Member 1264953131-Jul-16 21:30
Member 1264953131-Jul-16 21:30 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
ledtech31-Aug-16 4:59
ledtech31-Aug-16 4:59 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
Member 126495311-Aug-16 0:41
Member 126495311-Aug-16 0:41 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
ledtech31-Aug-16 5:15
ledtech31-Aug-16 5:15 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
Member 126495311-Aug-16 18:45
Member 126495311-Aug-16 18:45 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
ledtech31-Aug-16 18:55
ledtech31-Aug-16 18:55 
GeneralRe: getting warning at bounds and PictureBox1.Image.Save(SampleImage) for the following code Pin
Member 126495311-Aug-16 19:51
Member 126495311-Aug-16 19:51 
GeneralMy vote of 5 Pin
deo cabral2-Feb-15 19:45
professionaldeo cabral2-Feb-15 19:45 
GeneralRe: My vote of 5 Pin
ledtech32-Feb-15 23:28
ledtech32-Feb-15 23:28 
GeneralRe: My vote of 5 Pin
deo cabral2-Feb-15 23:37
professionaldeo cabral2-Feb-15 23:37 
GeneralRe: My vote of 5 Pin
ledtech32-Feb-15 23:39
ledtech32-Feb-15 23:39 
GeneralRe: My vote of 5 Pin
deo cabral3-Feb-15 3:55
professionaldeo cabral3-Feb-15 3:55 
GeneralRe: My vote of 5 Pin
ledtech33-Feb-15 14:07
ledtech33-Feb-15 14:07 
Questionvisaul basic not a update this code help me friends Pin
Naresh Gameti11-Oct-13 3:15
Naresh Gameti11-Oct-13 3:15 
SuggestionRe: visaul basic not a update this code help me friends Pin
ledtech311-Oct-13 3:29
ledtech311-Oct-13 3:29 
Questioncan we capture just the front window and not the background stuff Pin
RAJEEV_RSD25-Mar-12 16:21
RAJEEV_RSD25-Mar-12 16:21 
AnswerRe: can we capture just the front window and not the background stuff Pin
ledtech325-Mar-12 18:07
ledtech325-Mar-12 18:07 
AnswerRe: can we capture just the front window and not the background stuff Pin
stixoffire16-Oct-13 17:17
stixoffire16-Oct-13 17:17 
Get a handle to the front window (do a search for find foreground Windows Forms Handle ) - then after you have the handle you can bitmap it - and send to default printer.
QuestionAlternative Method Pin
GoodSyntax15-Mar-12 2:54
GoodSyntax15-Mar-12 2:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.