Click here to Skip to main content
15,886,362 members
Articles / Multimedia / GDI+

A complete C# Screensaver that does double-buffering on multiple monitor systems!

Rate me:
Please Sign up or sign in to vote.
4.75/5 (37 votes)
24 Jun 200534 min read 272.8K   1.8K   190  
Example screensaver in source code. Does a mini-preview too!
  • swarmscreensaver_src.zip
    • SwarmScreenSaver
      • CodeCommentReport
        • banner.htm
        • banner.jpg
        • CodeCommentReportError.htm
        • commentreport.css
        • CommonCode
        • darkcorner.jpg
        • gradleft.jpg
        • gradtop.jpg
        • graycorner.jpg
        • Insects
        • minus.jpg
        • plus.jpg
        • Solution_SwarmScreenSaver.HTM
        • SwarmScreenSaver
          • CWP0.HTM
          • CWP10.HTM
          • CWP100.HTM
          • CWP101.HTM
          • CWP102.HTM
          • CWP103.HTM
          • CWP104.HTM
          • CWP105.HTM
          • CWP106.HTM
          • CWP107.HTM
          • CWP108.HTM
          • CWP109.HTM
          • CWP11.HTM
          • CWP110.HTM
          • CWP111.HTM
          • CWP112.HTM
          • CWP113.HTM
          • CWP114.HTM
          • CWP115.HTM
          • CWP116.HTM
          • CWP117.HTM
          • CWP118.HTM
          • CWP119.HTM
          • CWP12.HTM
          • CWP120.HTM
          • CWP121.HTM
          • CWP122.HTM
          • CWP123.HTM
          • CWP124.HTM
          • CWP125.HTM
          • CWP126.HTM
          • CWP127.HTM
          • CWP128.HTM
          • CWP129.HTM
          • CWP13.HTM
          • CWP130.HTM
          • CWP131.HTM
          • CWP132.HTM
          • CWP134.HTM
          • CWP135.HTM
          • CWP136.HTM
          • CWP137.HTM
          • CWP138.HTM
          • CWP139.HTM
          • CWP14.HTM
          • CWP140.HTM
          • CWP141.HTM
          • CWP142.HTM
          • CWP143.HTM
          • CWP144.HTM
          • CWP145.HTM
          • CWP146.HTM
          • CWP147.HTM
          • CWP148.HTM
          • CWP149.HTM
          • CWP15.HTM
          • CWP150.HTM
          • CWP151.HTM
          • CWP152.HTM
          • CWP153.HTM
          • CWP154.HTM
          • CWP155.HTM
          • CWP156.HTM
          • CWP157.HTM
          • CWP158.HTM
          • CWP159.HTM
          • CWP16.HTM
          • CWP160.HTM
          • CWP161.HTM
          • CWP162.HTM
          • CWP163.HTM
          • CWP164.HTM
          • CWP165.HTM
          • CWP166.HTM
          • CWP167.HTM
          • CWP168.HTM
          • CWP169.HTM
          • CWP17.HTM
          • CWP170.HTM
          • CWP171.HTM
          • CWP172.HTM
          • CWP173.HTM
          • CWP174.HTM
          • CWP175.HTM
          • CWP176.HTM
          • CWP177.HTM
          • CWP178.HTM
          • CWP179.HTM
          • CWP18.HTM
          • CWP180.HTM
          • CWP181.HTM
          • CWP182.HTM
          • CWP183.HTM
          • CWP184.HTM
          • CWP185.HTM
          • CWP186.HTM
          • CWP187.HTM
          • CWP188.HTM
          • CWP189.HTM
          • CWP19.HTM
          • CWP190.HTM
          • CWP191.HTM
          • CWP192.HTM
          • CWP2.HTM
          • CWP20.HTM
          • CWP21.HTM
          • CWP22.HTM
          • CWP23.HTM
          • CWP24.HTM
          • CWP25.HTM
          • CWP26.HTM
          • CWP27.HTM
          • CWP28.HTM
          • CWP29.HTM
          • CWP3.HTM
          • CWP31.HTM
          • CWP32.HTM
          • CWP33.HTM
          • CWP34.HTM
          • CWP35.HTM
          • CWP36.HTM
          • CWP38.HTM
          • CWP39.HTM
          • CWP4.HTM
          • CWP40.HTM
          • CWP41.HTM
          • CWP42.HTM
          • CWP43.HTM
          • CWP44.HTM
          • CWP45.HTM
          • CWP46.HTM
          • CWP47.HTM
          • CWP48.HTM
          • CWP49.HTM
          • CWP5.HTM
          • CWP50.HTM
          • CWP51.HTM
          • CWP52.HTM
          • CWP53.HTM
          • CWP54.HTM
          • CWP55.HTM
          • CWP56.HTM
          • CWP57.HTM
          • CWP58.HTM
          • CWP59.HTM
          • CWP6.HTM
          • CWP60.HTM
          • CWP61.HTM
          • CWP62.HTM
          • CWP63.HTM
          • CWP64.HTM
          • CWP65.HTM
          • CWP66.HTM
          • CWP67.HTM
          • CWP68.HTM
          • CWP69.HTM
          • CWP7.HTM
          • CWP70.HTM
          • CWP71.HTM
          • CWP72.HTM
          • CWP73.HTM
          • CWP74.HTM
          • CWP75.HTM
          • CWP76.HTM
          • CWP77.HTM
          • CWP78.HTM
          • CWP79.HTM
          • CWP8.HTM
          • CWP80.HTM
          • CWP81.HTM
          • CWP82.HTM
          • CWP83.HTM
          • CWP84.HTM
          • CWP85.HTM
          • CWP86.HTM
          • CWP88.HTM
          • CWP9.HTM
          • CWP90.HTM
          • CWP91.HTM
          • CWP92.HTM
          • CWP93.HTM
          • CWP94.HTM
          • CWP95.HTM
          • CWP96.HTM
          • CWP97.HTM
          • CWP98.HTM
          • CWP99.HTM
          • SwarmScreenSaver.HTM
        • titletile.jpg
        • vt.js
      • CommonCode
      • Insects
      • SwarmScreenSaver.sln
      • SwarmScreenSaver
<!-- saved from url=(0014)about:Swarm -->
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<TITLE>SwarmScreenSaver.ScreenSaverForm</TITLE>
<LINK REL=STYLESHEET HREF="../CommentReport.css" TYPE="text/css">
</HEAD>
<BODY topmargin=0 rightmargin=0 leftmargin=0 style="background-image: url(../titletile.jpg); background-repeat:repeat-x; background-position: 0 0;" >
<DIV CLASS="PageHeading">SwarmScreenSaver.ScreenSaverForm Class</DIV>
<DIV CLASS="Description">

This ScreenSaverForm class is a form that is responsible for going full screen with a black background and<br>
then starting the paint event which is where You should put calls to your own screensaver calls.<br>
This form monitors keyboard and mouse to determine when to quit. There is an instance of this form for <br>
all active monitors.<br>
ScreenNumber is a variable that identifys the monitor this form is working with, and is use to get the bounds <br>
aka size of the monitor resolution. It now works with multiple monitors on the same system!. <br>
I know of no other screensaver in source or out of source that has succeded in this.<br>
the Insects class is the workhorse, and does all the graphics routines called in the paint event.
<P>

</DIV>
<IMG src="../GradLeft.jpg" width=7 height=378 alt="" border="0" style="position:absolute; left:10; top:18;z-Index:2">
<IMG src="../GradTop.jpg" width=352 height=7 alt="" border="0" align="top" style="position:absolute; left:10; top:18; z-index:1">
<DIV CLASS="Remarks">
<SPAN CLASS="RemarkHdrX">Access: </SPAN>Public</DIV>
<DIV CLASS="Remarks">
<SPAN CLASS="RemarkHdrX">Base Classes: </SPAN>Form</DIV>
<TABLE CLASS="InfoTable" cellpadding=0 cellspacing=0>
<TR height=20>
<TD width=20>&nbsp;</TD>
<TD valign=top align=left width=9 bgcolor="#cccc66"><IMG SRC="../graycorner.jpg" align=top></TD>
<TD CLASS="TableLightLabel" WIDTH=206>Members</TD>
<TD CLASS="TableLightLabel" >Description</TD>
<TD width=20>&nbsp;</TD>
</TR>
<TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP103.HTM" TARGET="CNTFRAME">paintStatus</A></TD>
<TD CLASS="TableLightDesc">
-4 Screen is shutting down!
-3 Error in painting.<br></br>
-2 Unwanted paint done.<br></br>
-1 No Activity.<br></br>
 0 Paint pending.<br></br>
 1 Our paint is in Paint event.<br></br>
 2 Ready to repaint.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP104.HTM" TARGET="CNTFRAME">paintMeCalled</A></TD>
<TD CLASS="TableLightDesc">
Seems we needed more than one status variable <br></br>
for painting. One for tracking paint status and another to indicate <br></br>
that my drawing code in paint  still needs to be executed.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP105.HTM" TARGET="CNTFRAME">components</A></TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP106.HTM" TARGET="CNTFRAME">MouseXY</A></TD>
<TD CLASS="TableLightDesc">
Contains the mouse position. If it moves, all instances os ScreenSaverFor are closed and the app is ended.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP107.HTM" TARGET="CNTFRAME">cf</A></TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP108.HTM" TARGET="CNTFRAME">DonePaintingDel</A></TD>
<TD CLASS="TableLightDesc">
A pair of delegates this form uses to send signals accross threads to the callers.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP109.HTM" TARGET="CNTFRAME">ShuttingDownDel</A></TD>
<TD CLASS="TableLightDesc">
Inform caller that the program needs to shut down.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP110.HTM" TARGET="CNTFRAME">ScreenNumber</A></TD>
<TD CLASS="TableLightDesc">
An index into the system array of active screens on the system: Screens.AllScreens[]
so that this screen can capture the monitor size as a bounds object.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP111.HTM" TARGET="CNTFRAME">stopNow</A></TD>
<TD CLASS="TableLightDesc">
stopNow starts out as false, when it becomes true due to mouse or key actions, the form closes.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP112.HTM" TARGET="CNTFRAME">SwarmCount</A></TD>
<TD CLASS="TableLightDesc">
Number of swarms per screen to show.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP113.HTM" TARGET="CNTFRAME">useStyleDoubleBuffer</A></TD>
<TD CLASS="TableLightDesc">
If true, use built-in control's double buffering. If you get InvalidOperationExceptions turn this off.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP114.HTM" TARGET="CNTFRAME">insects</A></TD>
<TD CLASS="TableLightDesc">
An array of drawing class instances. Each instance handles one swarm and one wasp.<br>
but there may be multiple swarms per screen.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP115.HTM" TARGET="CNTFRAME">memBitmap</A></TD>
<TD CLASS="TableLightDesc">
Memory resident bitmap for manual double bufferiing.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP116.HTM" TARGET="CNTFRAME">memGraphic</A></TD>
<TD CLASS="TableLightDesc">
A Grapics object for the the memory bitmap.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP117.HTM" TARGET="CNTFRAME">ScreenSaverForm</A></TD>
<TD CLASS="TableLightDesc">
Constructor for this form which is the central point for full screen drawing.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP118.HTM" TARGET="CNTFRAME">Dispose</A></TD>
<TD CLASS="TableLightDesc">
Dispose of any componants, dispose any of my dynamic objects, call base.Dispose.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP119.HTM" TARGET="CNTFRAME">ScreenSaverForm_Load</A></TD>
<TD CLASS="TableLightDesc">
Sets the size of this form to the size of the screen.<br>
then it hides the cursor. <br> 
sets this form to topmost. <br>
Informs the Insects instances of the size of the drawing area for this screen.<br>
Initializes the Insects instances. We need to do this separately. I could not do it in the constructor.<br>
The drawing objects are initialized in this load event, but are actually called in the paint event.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP120.HTM" TARGET="CNTFRAME">CloseMe</A></TD>
<TD CLASS="TableLightDesc">
 This is a centralized area, where the closing of this<br>
 form can be initiated from EntryPoints's Main method while<br>
 loop, and from inside this form itself.<br>
 It sets stopNow = true, and tells all insects instances<br>
 to stop drawing now.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP121.HTM" TARGET="CNTFRAME">OnMouseEvent</A></TD>
<TD CLASS="TableLightDesc">
OnMouseEvent. Has user moved or clicked the mouse?<br>
if so, set stopNow = true and close the form.<br>
Paint event will stop drawinig when stopNow = true<br>
and inform all insect instances to stop drawing.<br>
Initialize your drawing routines in the load event or earlier.<br>
Your drawing routines should go into the paint event.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP122.HTM" TARGET="CNTFRAME">ScreenSaverForm_KeyDown</A></TD>
<TD CLASS="TableLightDesc">
ScreenSaverForm_Keydown event. If use presses a key, close this form.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP123.HTM" TARGET="CNTFRAME">PaintMe</A></TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP124.HTM" TARGET="CNTFRAME">PaintStatus</A></TD>
<TD CLASS="TableLightDesc">
-4 Shutting down.
-3 Error in painting!.<br></br>
-2 Unwanted paint found.<br></br>
-1 No paint activity.<br></br>
 0 Paint event is pending.<br></br>
 1 A valid paint is in Paint event.<br></br>
 2 Ready to repaint.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP126.HTM" TARGET="CNTFRAME">InitializeComponent</A></TD>
<TD CLASS="TableLightDesc">
Required method for Designer support - do not modify 
the contents of this method with the code editor.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP127.HTM" TARGET="CNTFRAME">ScreenSaverForm_Paint</A></TD>
<TD CLASS="TableLightDesc">
Here is where you actually do the drawing stuff.<br> 
In this case, EntryPoint's Main method's while loop<br>
calls Refresh to get the screen to draw.<br>
The code takes the Graphics object in the paint argument <br>
and passes it to insects, my drawing class, which draws<br>
and the while loop calls Application.DoEvents to cause<br>
the painting that was done to show on the screens.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP128.HTM" TARGET="CNTFRAME">OnPaintBackground</A></TD>
<TD CLASS="TableLightDesc">
Don't allow background to paint.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP129.HTM" TARGET="CNTFRAME">OnSizeChanged</A></TD>
<TD CLASS="TableLightDesc">
Don't allow resizing.
<P>
</TD>
<TD width=20>&nbsp;</TD>
</TR><TR height=20>
<TD width=20>&nbsp;</TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD CLASS="TableLightDesc"><A HREF="CWP130.HTM" TARGET="CNTFRAME">OnForeColorChanged</A></TD>
<TD CLASS="TableLightDesc">&nbsp;</TD>
<TD width=20>&nbsp;</TD>
</TR></TABLE>
</BODY>
</HTML>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Hello, I have been a professional hairpuller aka programmer for a large company during the last nine years. The acquiring company is closing down the california office so I'll be out of work at the end of June at the latest. I program in a variety of laguages, C#, C++, C, Visual Basic, SQl Server among others. I live north of Sacramento in Paradise CA. I've been programming since the early 1980 and people accuse me of going bald. I'm not going bald, my hair is just migrating south and into my ears.

I am a firm believer that the most widely used programming language is #$@$@$%#$%^ but folks tend to object to the unusual synatax where each word has a colorful meaning and sentences are limited to three words max, while the punching bag flys back and forth so fast it heats up from friction like a meteorite through the air.

In short, I'm nuts, but I'm good at what I do.

Programming is like beating my head against a brick wall, it hurts so bad I can't stand it, but when I stop beating my head against the wall (Solve the problem), it feels so good I gotta do it again!

Comments and Discussions