记得这段代码我是在看了Windows C制作异型窗体的原理后写出来的。主要就是传一个Form的对象和一个Bitmap对象给SetWindowRegion方法,SetWindowRegion方法就会完成设置。
传的图片要有一个透明色,如果没有设置透明色,就会以图片(0,0)像素的颜色为透明色。具体的实现过程就是扫描图片的每个象素,如果这个像素的颜色和透明色不一样就往一个GraphicsPath对象里添加一个1×1的小矩形,当扫描完所有象素后,就利用这个GraphicsPath对象生成一个Region对象,然后把这个Region赋给窗体对象即可。
using
System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class Common
... {
/**//// <summary>
/// 设置窗体为不规则界面
/// </summary>
/// <remarks>根据背景图片来设置窗体的形状,
/// 以背景图片的(0, 0)位置为透明色</remarks>
/// <param name="MainForm">要设置的窗体</param>
/// <param name="BmpBack">设置形状所依据的图片</param>
public static void SetWindowRegion(Form MainForm,
Bitmap BmpBack)
...{
Color TransparentColor;
TransparentColor = BmpBack.GetPixel(0, 0);
SetWindowRegion(MainForm, BmpBack, TransparentColor);
}
/**//// <summary>
/// 设置窗体为不规则界面
/// </summary>
/// <param name="MainForm">要设置的窗体</param>
/// <param name="BmpBack">设置形状所依据的图片</param>
/// <param name="TransparentColor">图片的透明色</param>
public static void SetWindowRegion(Form MainForm,
Bitmap BmpBack, Color TransparentColor)
...{
Color TempColor;
GraphicsPath gp;
gp = new GraphicsPath();
MainForm.FormBorderStyle = FormBorderStyle.None;
MainForm.Width = BmpBack.Width;
MainForm.Height = BmpBack.Height;
MainForm.BackgroundImage = BmpBack;
for (int nX = 0; nX < BmpBack.Width; nX++)
...{
for (int nY = 0; nY < BmpBack.Height; nY++)
...{
TempColor = BmpBack.GetPixel(nX, nY);
if (TempColor != TransparentColor)
...{
gp.AddRectangle(new Rectangle(nX, nY, 1, 1));
}
}
}
MainForm.Region = new Region(gp);
}
}
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public class Common
... {
/**//// <summary>
/// 设置窗体为不规则界面
/// </summary>
/// <remarks>根据背景图片来设置窗体的形状,
/// 以背景图片的(0, 0)位置为透明色</remarks>
/// <param name="MainForm">要设置的窗体</param>
/// <param name="BmpBack">设置形状所依据的图片</param>
public static void SetWindowRegion(Form MainForm,
Bitmap BmpBack)
...{
Color TransparentColor;
TransparentColor = BmpBack.GetPixel(0, 0);
SetWindowRegion(MainForm, BmpBack, TransparentColor);
}
/**//// <summary>
/// 设置窗体为不规则界面
/// </summary>
/// <param name="MainForm">要设置的窗体</param>
/// <param name="BmpBack">设置形状所依据的图片</param>
/// <param name="TransparentColor">图片的透明色</param>
public static void SetWindowRegion(Form MainForm,
Bitmap BmpBack, Color TransparentColor)
...{
Color TempColor;
GraphicsPath gp;
gp = new GraphicsPath();
MainForm.FormBorderStyle = FormBorderStyle.None;
MainForm.Width = BmpBack.Width;
MainForm.Height = BmpBack.Height;
MainForm.BackgroundImage = BmpBack;
for (int nX = 0; nX < BmpBack.Width; nX++)
...{
for (int nY = 0; nY < BmpBack.Height; nY++)
...{
TempColor = BmpBack.GetPixel(nX, nY);
if (TempColor != TransparentColor)
...{
gp.AddRectangle(new Rectangle(nX, nY, 1, 1));
}
}
}
MainForm.Region = new Region(gp);
}
}
上代码执行时,如果图片比较小,生成异型窗体速度是非常快的,但如果图片比较大就很慢了。
后来实在无法忍受,在网上找到一个通过不安全代码实现的,把这个代码也贴出来:
/**/
///<author>Arild Fines</author>
///<date>20.04.2002</date>
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace Spider.Common
... {
/**//// <summary>
/// determines the meaning of the transparencyKey argument to the Convert method
/// </summary>
public enum TransparencyMode
...{
/**//// <summary>
/// the color key is used to define the transparent region of the bitmap
/// </summary>
ColorKeyTransparent,
/**//// <summary>
/// the color key is used to define the area that should _not_ be transparent
/// </summary>
ColorKeyOpaque
}
/**//// <summary>
/// a class to convert a color-keyed bitmap into a region
/// </summary>
public class BitmapToRegion
...{
/**//// <summary>
/// ctor made private to avoid instantiation
/// </summary>
private BitmapToRegion()
...{ }
/**//// <summary>
/// the meat of this class
/// converts the bitmap to a region by scanning each line one by one
/// this method will not affect the original bitmap in any way
/// </summary>
/// <param name="bitmap">The bitmap to convert</param>
/// <param name="transparencyKey">The color which will indicate either transparency or opacity</param>
/// <param name="mode">Whether the transparency key should indicate the transparent or the opaque region</param>
public unsafe static Region Convert(Bitmap bitmap, Color transparencyKey, TransparencyMode mode)
...{
//sanity check
if (bitmap == null)
throw new ArgumentNullException("Bitmap", "Bitmap cannot be null!");
//flag = true means the color key represents the opaque color
bool modeFlag = (mode == TransparencyMode.ColorKeyOpaque);
GraphicsUnit unit = GraphicsUnit.Pixel;
RectangleF boundsF = bitmap.GetBounds(ref unit);
Rectangle bounds = new Rectangle((int) boundsF.Left, (int) boundsF.Top,
(int) boundsF.Width, (int) boundsF.Height);
uint key = (uint) ((transparencyKey.A << 24) | (transparencyKey.R << 16) |
(transparencyKey.G << 8) | (transparencyKey.B << 0));
//get access to the raw bits of the image
BitmapData bitmapData = bitmap.LockBits(bounds, ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
uint* pixelPtr = (uint*) bitmapData.Scan0.ToPointer();
//avoid property accessors in the for
int yMax = (int) boundsF.Height;
int xMax = (int) boundsF.Width;
//to store all the little rectangles in
GraphicsPath path = new GraphicsPath();
for (int y = 0; y < yMax; y++)
...{
//store the pointer so we can offset the stride directly from it later
//to get to the next line
byte* basePos = (byte*) pixelPtr;
for (int x = 0; x < xMax; x++, pixelPtr++)
...{
//is this transparent? if yes, just go on with the loop
if (modeFlag ^ (*pixelPtr == key))
continue;
//store where the scan starts
int x0 = x;
//not transparent - scan until we find the next transparent byte
while (x < xMax && !(modeFlag ^ (*pixelPtr == key)))
...{
++x;
pixelPtr++;
}
//add the rectangle we have found to the path
path.AddRectangle(new Rectangle(x0, y, x - x0, 1));
}
//jump to the next line
pixelPtr = (uint*) (basePos + bitmapData.Stride);
}
//now create the region from all the rectangles
Region region = new Region(path);
//clean up
path.Dispose();
bitmap.UnlockBits(bitmapData);
return region;
}
}
}
///<date>20.04.2002</date>
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace Spider.Common
... {
/**//// <summary>
/// determines the meaning of the transparencyKey argument to the Convert method
/// </summary>
public enum TransparencyMode
...{
/**//// <summary>
/// the color key is used to define the transparent region of the bitmap
/// </summary>
ColorKeyTransparent,
/**//// <summary>
/// the color key is used to define the area that should _not_ be transparent
/// </summary>
ColorKeyOpaque
}
/**//// <summary>
/// a class to convert a color-keyed bitmap into a region
/// </summary>
public class BitmapToRegion
...{
/**//// <summary>
/// ctor made private to avoid instantiation
/// </summary>
private BitmapToRegion()
...{ }
/**//// <summary>
/// the meat of this class
/// converts the bitmap to a region by scanning each line one by one
/// this method will not affect the original bitmap in any way
/// </summary>
/// <param name="bitmap">The bitmap to convert</param>
/// <param name="transparencyKey">The color which will indicate either transparency or opacity</param>
/// <param name="mode">Whether the transparency key should indicate the transparent or the opaque region</param>
public unsafe static Region Convert(Bitmap bitmap, Color transparencyKey, TransparencyMode mode)
...{
//sanity check
if (bitmap == null)
throw new ArgumentNullException("Bitmap", "Bitmap cannot be null!");
//flag = true means the color key represents the opaque color
bool modeFlag = (mode == TransparencyMode.ColorKeyOpaque);
GraphicsUnit unit = GraphicsUnit.Pixel;
RectangleF boundsF = bitmap.GetBounds(ref unit);
Rectangle bounds = new Rectangle((int) boundsF.Left, (int) boundsF.Top,
(int) boundsF.Width, (int) boundsF.Height);
uint key = (uint) ((transparencyKey.A << 24) | (transparencyKey.R << 16) |
(transparencyKey.G << 8) | (transparencyKey.B << 0));
//get access to the raw bits of the image
BitmapData bitmapData = bitmap.LockBits(bounds, ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
uint* pixelPtr = (uint*) bitmapData.Scan0.ToPointer();
//avoid property accessors in the for
int yMax = (int) boundsF.Height;
int xMax = (int) boundsF.Width;
//to store all the little rectangles in
GraphicsPath path = new GraphicsPath();
for (int y = 0; y < yMax; y++)
...{
//store the pointer so we can offset the stride directly from it later
//to get to the next line
byte* basePos = (byte*) pixelPtr;
for (int x = 0; x < xMax; x++, pixelPtr++)
...{
//is this transparent? if yes, just go on with the loop
if (modeFlag ^ (*pixelPtr == key))
continue;
//store where the scan starts
int x0 = x;
//not transparent - scan until we find the next transparent byte
while (x < xMax && !(modeFlag ^ (*pixelPtr == key)))
...{
++x;
pixelPtr++;
}
//add the rectangle we have found to the path
path.AddRectangle(new Rectangle(x0, y, x - x0, 1));
}
//jump to the next line
pixelPtr = (uint*) (basePos + bitmapData.Stride);
}
//now create the region from all the rectangles
Region region = new Region(path);
//clean up
path.Dispose();
bitmap.UnlockBits(bitmapData);
return region;
}
}
}
以上代码的使用类似于我写的代码,只不过这个需要在窗体类里自己将RegionConvert方法返回来到Region设置给窗体的Region属性。