本文介绍DotNet中PictureBox控件实现重叠透明效果示例。
关于一般的透明效果,这里不多说,相信很多人都会,这种透明效果一般需要设置父控件,是子控件相对于父控件的透明。那么很多人可能更为关心的是多个控件之间的透明效果,比如窗体上有多个PictureBox控件,当这些PictureBox重叠时如何设置为透明,这样的效果估计在项目中会经常用到。本文的目的就是要给大家提供几种参考解决方案。
一般地,在.NET中,多个控件之间重叠时是不会实现透明效果的。 如下图所示:
下面开始介绍这几种解决方案:
第一种方案:记录不透明图片的路径,再设置透明效果。参考代码如下:
/// <summary>
///
PictureBox透明示例
///
Date:2012-3-4 07:25:56
///
</summary>
public
partial
class Form1 : Form
{
[DllImport(
"
user32.dll
")]
public
static
extern
int ReleaseCapture();
[DllImport(
"
user32.dll
")]
public
static
extern
int SendMessage(IntPtr hwnd,
int wMsg,
int wParam,
int lParam);
public
const
int WM_SYSCOMMAND =
0x0112;
public
const
int SC_MOVE =
0xF010;
public
const
int HTCAPTION =
0x0002;
public Form1()
{
InitializeComponent();
//
this.picModelImage.Controls.Add(this.picHair);
}
private
void picHair_MouseDown(
object sender, MouseEventArgs e)
{
SetPictureBoxTransparent(picHair, picHair.Image);
//
SetPictureBoxTransparent(picModelImage, picModelImage.Image);
ReleaseCapture();
SendMessage(
this.picHair.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION,
0);
}
//
使用不安全的指针
//
返回不透明的图片路径
private
unsafe GraphicsPath NoteGraphicsPath(Image image)
{
if (image ==
null)
return
null;
//
声明GraphicsPath类以便计算位图路径
GraphicsPath graphicsPath =
new GraphicsPath(FillMode.Alternate);
Bitmap bitmap =
new Bitmap(image);
int picWidth = bitmap.Width;
int picHeight = bitmap.Height;
BitmapData bitmapdata = bitmap.LockBits(
new Rectangle(
0,
0, picWidth, picHeight), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte* point = (
byte*)bitmapdata.Scan0;
int offset = bitmapdata.Stride - picWidth *
3;
int p0, p1, p2;
p0 = point[
0];
p1 = point[
1];
p2 = point[
2];
int start = -
1;
for (
int h =
0; h < picHeight; h++)
{
for (
int x =
0; x < picWidth; x++)
{
//
如果之前的点没有不透明且不透明
if (start == -
1 && (point[
0] != p0 || point[
1] != p1 || point[
2] != p2))
{
start = x;
}
else
if (start > -
1 && (point[
0] == p0 && point[
1] == p1 && point[
2] == p2))
{
//
如果之前的点是不透明
graphicsPath.AddRectangle(
new Rectangle(start, h, x - start -
1,
1));
start = -
1;
}
//
如果之前的点是不透明且是最后一个点
if (x == picWidth -
1 && start > -
1)
{
graphicsPath.AddRectangle(
new Rectangle(start, h, x - start +
1,
1));
start = -
1;
}
point +=
3;
}
point += offset;
}
bitmap.UnlockBits(bitmapdata);
bitmap.Dispose();
return graphicsPath;
}
///
<summary>
///
需要设置透明效果的控件调用该方法
///
</summary>
///
<param name="control">
要设置透明效果的控件
</param>
///
<param name="image">
控件的图片
</param>
public
void SetPictureBoxTransparent(Control control, Image image)
{
GraphicsPath graphic =
null;
graphic = NoteGraphicsPath(image);
if (graphic ==
null)
return;
control.Region =
new Region(graphic);
}
}
需要添加2个命名空间:
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
运行后效果如下所示:

注意:由于本示例有不安全的代码[关键字unsafe],需要在项目属性中设置"允许不安全代码",如下图:
第二种方案:使用GDI +中绘制图像与透明
这种方案是需要我使用GDI+绘制图像,具体步骤如下所示:
1. 需要添加两个组件类:
PictureBoxModel.cs 和 PanelExtend.cs
PanelExtend.cs 中代码:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
///
<summary>
///
Panel扩展类
///
</summary>
public
abstract
class PanelExtend : Panel
{
protected Graphics graphics;
protected
override CreateParams CreateParams
{
get
{
CreateParams cp =
base.CreateParams;
cp.ExStyle |=
0x00000020;
//
实现透明样式
return cp;
}
}
public PanelExtend()
{
}
protected
override
void OnPaintBackground(PaintEventArgs pevent)
{
}
protected
override
void OnPaint(PaintEventArgs e)
{
this.graphics = e.Graphics;
this.graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
this.graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
this.graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
this.graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
OnDraw();
}
protected
abstract
void OnDraw();
}
PictureBoxModel.cs 代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
///
<summary>
///
实现绘制图像
///
</summary>
public
class PictureBoxModel : PanelExtend
{
public PictureBoxModel()
{
//
this.SetStyle(System.Windows.Forms.ControlStyles.SupportsTransparentBackColor, true);
}
protected
override
void OnDraw()
{
//
获取图像
Image imageModel =
global::MyPictureBoxDemo.Properties.Resources.model;
Image imageHair =
global::MyPictureBoxDemo.Properties.Resources.hair;
//
int width = imageModel.Size.Width;
//
int height = imageModel.Size.Height;
int width =
this.Width;
int height =
this.Height;
Rectangle recModel =
new Rectangle(
0,
0, width, height);
Rectangle recHair =
new Rectangle(
0,
0, imageHair.Width, imageHair.Height);
this.graphics.DrawImage(imageModel, recModel);
this.graphics.DrawImage(imageHair, recHair);
}
}
实现效果图如下所示:
示例下载:点击下载
第三种方案: 移动图片时使用GDI清除背景并实时刷新
我这里实现了这种方案,但是在移动图片时存在着闪烁现象。希望谁能有更好的解决方案可以一起交流。 效果图如下:

主要是在程序中未执行PictureBox_MouseUp事件。
示例下载:点击下载
最后,希望转载的朋友能够尊重作者的劳动成果,加上转载地址:http://www.cnblogs.com/hanyonglu/archive/2012/04/04/2431625.html 谢谢。
完毕。^_^