DotNet实现PictureBox重叠透明效果

  本文介绍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(00, 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 - 11));
                        start = -1;
                    }

                    // 如果之前的点是不透明且是最后一个点  
                    if (x == picWidth - 1 && start > -1)
                    {
                        graphicsPath.AddRectangle(new Rectangle(start, h, x - start + 11));
                        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(00, width, height);
        Rectangle recHair = new Rectangle(00, 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 谢谢。

 

  完毕。^_^

posted @ 2012-04-04 01:31 Healtheon 阅读(...) 评论(...) 编辑 收藏