|
|||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionI had to create transparent fuzzy drop shadows similar to those found in various windows applications for a project I'm working on. Want to have them too? then read on! (or just download the sources) BackgroundUnfortunately, there's no support at all for these drop shadows in Visual Studio 2005/Winforms. (there is in WPF!). Fortunately, I only needed panels with shadows. And shadows for rectangular shapes are easy. I just took the method I use for webpages and applied it to winforms. The trick is as follows. Using strategically placed and tiled pictures of a shadow, we can simulate one. When transparent .PNG's are used, it looks just like the real thing. The image parts we need are outlined in red below:
Normally, I'd start with creating these images. Luckily for you, I actually did that and I provided them with the sources. Time to start coding! The projectFile > New > Project and select Class Library. Call it ShadowPanel and click OK. Now rename the class1.cs to ShadowPanel.cs. That's the file we'll work with. PropertiesFirst, we need some properties. It would be nice to provide at least a border and a background color. Time to open ShadowPanel.cs and add the following: using System;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace ShadowPanel
{
public class ShadowPanel : Panel
{
private Color _panelColor;
public Color PanelColor
{
get { return _panelColor; }
set { _panelColor = value; }
}
private Color _borderColor;
public Color BorderColor
{
get { return _borderColor; }
set { _borderColor = value; }
}
We can't use the original panel ImagesNow for the images we can use to actually draw the shadow. You can download them with the sources if you didn't do this already. Create a folder in the project called 'Images' and add the tshadowXXXX.png files. Select them in the solution explorer, and change the Build Action to Embedded resource. That way the files will be compiled into the .dll and you won't need to distribute them with your application. private int shadowSize = 5;
private int shadowMargin = 2;
// static for good performance
static Image shadowDownRight = new Bitmap(typeof(ShadowPanel), "Images.tshadowdownright.png");
static Image shadowDownLeft = new Bitmap(typeof(ShadowPanel), "Images.tshadowdownleft.png");
static Image shadowDown = new Bitmap(typeof(ShadowPanel), "Images.tshadowdown.png");
static Image shadowRight = new Bitmap(typeof(ShadowPanel), "Images.tshadowright.png");
static Image shadowTopRight = new Bitmap(typeof(ShadowPanel), "Images.tshadowtopright.png");
OnPaint()Everything is prepared for us to do the cool stuff. Creating GDI+ drawing code! Let's override the OnPaint method of the Panel base class: protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Get the graphics object. We need something to draw with
Graphics g = e.Graphics;
First we'll do the tiled images on the bottom and the right:
I think the code says it all. Just add after // Create tiled brushes for the shadow on the right and at the bottom.
TextureBrush shadowRightBrush = new TextureBrush(shadowRight, WrapMode.Tile);
TextureBrush shadowDownBrush = new TextureBrush(shadowDown, WrapMode.Tile);
// Translate (move) the brushes so the top or left of the image matches the top or left of the
// area where it's drawed. If you don't understand why this is necessary, comment it out.
// Hint: The tiling would start at 0,0 of the control, so the shadows will be offset a little.
shadowDownBrush.TranslateTransform(0, Height - shadowSize);
shadowRightBrush.TranslateTransform(Width - shadowSize, 0);
// Define the rectangles that will be filled with the brush.
// (where the shadow is drawn)
Rectangle shadowDownRectangle = new Rectangle(
shadowSize + shadowMargin, // X
Height - shadowSize, // Y
Width - (shadowSize * 2 + shadowMargin), // width (stretches)
shadowSize // height
);
Rectangle shadowRightRectangle = new Rectangle(
Width - shadowSize, // X
shadowSize + shadowMargin, // Y
shadowSize, // width
Height - (shadowSize * 2 + shadowMargin) // height (stretches)
);
// And draw the shadow on the right and at the bottom.
g.FillRectangle(shadowDownBrush, shadowDownRectangle);
g.FillRectangle(shadowRightBrush, shadowRightRectangle);
You can add the ShadowPanel to the test project by opening the Form1.cs designer. If you build the project once, the ShadowPanel should appear in the toolbox. Just drag it to the form and run it. You'll (hopefully) get the following result:
By the way, I set my form's background color to white, so it might look different for you. Bring in the cornersTo draw the small bitmaps in the corners, just add the following: // Now for the corners, draw the 3 5×5 pixel images.
g.DrawImage(shadowTopRight, new Rectangle(Width - shadowSize, shadowMargin, shadowSize, shadowSize));
g.DrawImage(shadowDownRight, new Rectangle(Width - shadowSize, Height - shadowSize, shadowSize, shadowSize));
g.DrawImage(shadowDownLeft, new Rectangle(shadowMargin, Height - shadowSize, shadowSize, shadowSize));
Almost too easy. Filling and bordering.We already have the // Fill the area inside with the color in the PanelColor property.
// 1 pixel is added to everything to make the rectangle smaller.
// This is because the 1 pixel border is actually drawn outside the rectangle.
Rectangle fullRectangle = new Rectangle(
1, // X
1, // Y
Width - (shadowSize + 2), // Width
Height - (shadowSize + 2) // Height
);
if (PanelColor != null)
{
SolidBrush bgBrush = new SolidBrush(_panelColor);
g.FillRectangle(bgBrush, fullRectangle);
}
// Draw a nice 1 pixel border it a BorderColor is specified
if (_borderColor != null)
{
Pen borderPen = new Pen(BorderColor);
g.DrawRectangle(borderPen, fullRectangle);
}
Time to check our results so far:
Well, that's about it. We're almost done. Finishing upJust a formality, end the OnPaint method with: // Memory efficiency
shadowDownBrush.Dispose();
shadowRightBrush.Dispose();
shadowDownBrush = null;
shadowRightBrush = null;
}
}
}
Done! Points of InterestOf course, I won't stop you from adding more functionality. Please do! And let me know if you appreciated this tutorial! HistoryJune 17th - First version
|
||||||||||||||||||||||||||||||||||||||||