Introduction
This is a simple project that demonstrates how easy it is to create a
custom shaped form that has a drop down in .NET using very little code.
This is a VS2003 project but it should work in VS2005 or C# Express with
few modifications.
I had found code that demonstrated the basic principle, but I needed
something with the potential to be dynamic. Transparency did not work for
most of the samples I found in 32 bit mode so I went searching on MSDN and
found a code snippet that loaded images with transparency, and it was all
done in C#.
What you see above is the initial screen when the program loads. What you
don't see is the actual size of the form which is actually 300 pixels by 200
pixels, much larger than the image above. Also when you run it, clicking
around the image will either bring up the window behind the image, or in this
case do nothing since there is no window behind it. When you mouse over it,
you will see a drop down which is also click-able.
Some of you may recognize the images. In fact this started out as an older
VB7 project created by somebody else (I can't remember who) which
demonstrated what this project does. However, transparency did not work in 32
bit mode plus it had an additional class to handle the clipping and graphics,
most of which I discovered you don't need.
Using the code
To start with, create a borderless form of any size. It must be big enough to hold the largest image. Borderless allows for invisibility.
Set the transparency key of the form to some color you won't be using
elsewhere. It is not necessary to set it to the same transparency color as
the image(s).
The heart of the code is 5 lines as shown below (excluding comments)
executed in the paint event.
bmp is a private bitmap variable declared at the class
level.
private void Form1_Paint(object sender, PaintEventArgs e)
{
ImageAttributes attr = new ImageAttributes();
attr.SetColorKey(bmp.GetPixel(0, 0), bmp.GetPixel(0, 0));
e.Graphics.FillRectangle(Brushes.Transparent,this.DisplayRectangle);
GraphicsUnit pu = GraphicsUnit.Pixel;
e.Graphics.DrawImage((Image)bmp, Rectangle.Truncate(
bmp.GetBounds(ref pu)), 0F, 0F, (float)bmp.Width,
(float)bmp.Height,
GraphicsUnit.Pixel, attr);
}
To make the drop down, I actually load a different image that includes the
original image. I do this with the MouseEnter event of the form.
private void Form1_MouseEnter(object sender , EventArgs e )
{
bmp = (Bitmap)Bitmap.FromFile("Sonique Small Extended.bmp");
this.Invalidate();
}
I then switch back to the original image on the MouseLeave event of the form.
private void Form1_MouseLeave(object sender , EventArgs e )
{
bmp = (Bitmap)Bitmap.FromFile("Sonique Small.bmp");
this.Invalidate();
}
I also included some code to simulate an exit button, which is the "x" button on the drop down image.
private void Form1_MouseUp(object sender,
System.Windows.Forms.MouseEventArgs e)
{
Point p=new Point(e.X,e.Y);
if (ExitButton(p))
this.Close();
}
private bool ExitButton(Point p)
{
int left = 157;
int right = 168;
int top = 28;
int bottom = 39;
return (p.X >= left && p.X <= right
&& p.Y >= top && p.Y <= bottom);
}
Points of Interest
Comment out the line that draws the image. When you run it, you will never
see the form plus you can't click on it, as if it didn't exist.
Also notice I don't have any code to set the region and clipping - it's not needed. Moreover, I don't use any calls to the Win32 api - it is all C#.
Possible Improvements
There is a lot missing here. My point was to show how to create a custom
form, but you will undoubtedly need more controls. You could add custom
controls, examples of which you can find on CodeProject, or make use of my
example here. I also included a simple project to determine the mouse
boundaries needed for this example.
If you do add custom controls, you need to modify either the
MouseLeave or MouseEnter events so the
particular image will stay put while you process control events.
I load the images in real time, and you will see it is pretty snappy.
If, when you experiment, you find it slows down because of large images or
too many images, try creating a bitmap array on Form_load
and keep them in memory, and if needed use double buffering. There is a lot
you can do to improve this.
I have been programming since 1986, in c, c++,basic, Visual Basic and now Dotnet.