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 application 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 was wanting 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 thru to get it to work. So I downloaded and installed the Visual Basic Power pack 3.
After some reading, trial, and allot 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 the form.
C# and converted VB.NET code:
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
{
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 a 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 MS 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 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 MS Paint from code to to open the file.)
Final code for screen capture test:
Private Sub GetScreenshot_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles GetScreenshot.Click
Dim graph As Graphics = Nothing Try
Dim frmleft As System.Drawing.Point = Me.Bounds.Location
Dim bmp As New Bitmap(Me.Bounds.Width + 8, Me.Bounds.Height + 8)
graph = Graphics.FromImage(bmp)
Dim screeny As Integer = frmleft.Y
graph.CopyFromScreen(screenx - 5, screeny - 5, 0, 0, bmp.Size)
bmp.Save("C:\temp.png")
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 MS 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 MS 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 MS 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:
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
AddHandler PrintDocument2.PrintPage, AddressOf Me.printDocument2_PrintPage
Me.PrintPreviewDialog1.Document = Me.PrintDocument2
End Sub
Private Sub printDocument2_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs)
Dim prnborderX As Single
prnborderX = PrintDocument2.DefaultPageSettings.PrintableArea.X + 1
Dim prnborderY As Single
prnborderY = PrintDocument2.DefaultPageSettings.PrintableArea.Y + 10
Dim pagewidth As Single
pagewidth = PrintDocument2.DefaultPageSettings.PrintableArea.Width
Dim pageHeight As Single
pageHeight = PrintDocument2.DefaultPageSettings.PrintableArea.Height
Dim br As SolidBrush = New SolidBrush(Color.Black)
Dim p As Pen = New Pen(Color.Black)
Dim g As Pen = New Pen(Color.CornflowerBlue)
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)
e.Graphics.DrawString(prndoc2default, f, Brushes.Black, 50, 90)
e.Graphics.DrawRectangle(p, 50, 150, 300, 150)
e.Graphics.DrawRectangle(g, prnborderX, prnborderY, pagewidth - 50, pageHeight - 25)
Dim drawImg As New Bitmap("C:\temp.png")
Dim mgHeight As Single = drawImg.Height
Dim mgWidth As Single = drawImg.Width
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)
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:
- Outputs an Outline Box just inside of the the printable area, to help see where the printable area is as laid out on the print preview control.
- Prints the paper size of the default printer as a string.
- Prints the Printable Area of the default printer, (this may be different for each individual printer).
- Draws a box (left over from some test code).
- Then paints the image scaled to the width of the printable area. I used the 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.
Lets see what the output looks like:
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.
FormScreenshotPrint.zip
Do 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 the 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