专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > .NET组件控件

在 .NET 中怎么实现真正的透明控件

发布时间:2011-06-24 19:08:49 文章来源:www.iduyao.cn 采编人员:星星草
在 .NET 中如何实现真正的透明控件
.NET 里的控件背景色所谓的“透明背景”是通过绘制父控件的背景实现的,并不是真正的透明效果。
因此,当多个具有透明背景色的同级控件重叠时,Z 顺序位于前面的控件会遮挡住 Z 顺序小于它的控件。

现在我想要做一个能够真正实现透明背景的控件,思路如下:

1、模仿微软的做法,把和自己相交的控件的部分绘制为背景色

或者

2、使用传说中的 SetLayeredWindowAttribute 方法(未尝试过)。

对于方法1,在实施的时候出现了一些问题。

我新建了控件,继承于 Panel ,重写了控件的 OnPaitBackground 方法,代码如下:
C# code

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            paintingBg = true;
            base.OnPaintBackground(pevent);
            PaintTransparentBackground(pevent);
            paintingBg = false;
        }
        protected internal void PaintTransparentBackground(PaintEventArgs pevent)
        {
            Graphics g = pevent.Graphics;
            Rectangle myBounds = Bounds;
            foreach (Control ctrl in Parent.Controls)
            {
                if (ctrl != this && ctrl.Visible)
                {
                    TransparentControl overlappedCtrl = ctrl as TransparentControl;
                    if (null == overlappedCtrl || overlappedCtrl.paintingBg)
                    {
                        if (null == overlappedCtrl)
                        {
                            ctrl.Invalidate();
                        }
                        continue;
                    }
                    g.ResetTransform();
                    PaintOverlappedControl(pevent, ctrl);
                }
            }
            g.ResetClip();
        }
        private void PaintOverlappedControl(PaintEventArgs pe, Control overlappedCtrl)
        {
            Graphics g = pe.Graphics;
            Rectangle ctrlRect = overlappedCtrl.Bounds;
            if (ctrlRect.IntersectsWith(Bounds))
            {
                Rectangle overlappedRect = Rectangle.Intersect(ctrlRect, Bounds);
                Point clipLeftTop = new Point(overlappedRect.Left - Left, overlappedRect.Top - Top);
                Rectangle clipRect = new Rectangle(clipLeftTop, overlappedRect.Size);
                Point orign = new Point(ctrlRect.Left - Left, ctrlRect.Top - Top);
                Rectangle viewRect = new Rectangle(orign, overlappedRect.Size);
                //g.SetClip(clipRect);
                //g.TranslateClip(-orign.X, -orign.Y);
                //g.RenderingOrigin = new Point(-orign.X, - orign.Y);
                using (PaintEventArgs args = new PaintEventArgs(g, clipRect))
                {
                    this.InvokePaintBackground(overlappedCtrl, args);
                    this.InvokePaint(overlappedCtrl, args);
                }
                Region rgn = new Region(ctrlRect);
                rgn.Exclude(overlappedRect);
                overlappedCtrl.Invalidate(rgn, true);
            }
        }



上面这段代码的没有达到实际的效果,而是这样的怪异效果:
·如果控件和别的控件相交,原先控件的背景没了(如果不和其它控件相交,则正常)
·相交区域绘制的位置总是不正确(我以及多次调整过剪辑区域的位置,均没达到正确的效果)
·控件的文本总是绘制在不正确的位置上。
·如果控件 A 和控件 B 有相交的区域,现在移动控件 B,控件 B 的背景会被刷新,但是控件 A 的背景不被刷新。

哪位高手帮看一下代码出了什么问题,或者给出一个其它的解决方案,谢了~


------解决方案--------------------
LZ可以送10分技术分给我吗?急用`谢谢啦`好心有好报!
------解决方案--------------------
用以下类可以搞定。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace GISUtilities
{
public class AlphaBlend
{
// Methods
public AlphaBlend()
{
}

public void AlphaBlendNumber(IntPtr Handle, short Num)
{
AlphaBlend.SetLayeredWindowAttributes(Handle, 0, (byte)Num, 2);
}

public void AlphaBlendPercent(IntPtr Handle, short Percent)
{
AlphaBlend.SetLayeredWindowAttributes(Handle, 0, (byte)Math.Round((double)((((double)Percent) / 100) * 255)), 2);
}

public IntPtr FindApplicationWindow([Optional] string WindowClass /* = null */, [Optional] string WindowTitle /* = null */)
{
return AlphaBlend.FindWindow(WindowClass, WindowTitle);
}

[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowLong(IntPtr Handle, int nIndex);

public void ResetAlphaBlending(IntPtr Handle)
{
int num1 = AlphaBlend.GetWindowLong(Handle, -20);
// The following line has me stumped, in VB, the const WS_EX_LAYERED breaks down to the value 524288
// Yet on the line below is the same number but increased by one, basically it should (boolean here) num1 and not WS_EX_LAYERED
AlphaBlend.SetWindowLong(Handle, -20, num1 & -524289);
}

[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int SetLayeredWindowAttributes(IntPtr Handle, int crKey, byte bAlpha, int dwFlags);

public void SetupAlphaBlending(IntPtr Handle)
{
int num1 = AlphaBlend.GetWindowLong(Handle, -20);
num1 |= WS_EX_LAYERED;
AlphaBlend.SetWindowLong(Handle, -20, num1);
}

[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int SetWindowLong(IntPtr Handle, int nIndex, int dwNewLong);


// Fields
private const short GWL_EXSTYLE = -20;
private const short LWA_ALPHA = 2;
private const short LWA_COLORKEY = 1;
private const int WS_EX_LAYERED = 0x80000;
}
}

------解决方案--------------------
C# code
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace GISUtilities
{
    public class AlphaBlend
    {
        // Methods
        public AlphaBlend()
        {
        }

        public void AlphaBlendNumber(IntPtr Handle, short Num)
        {
            AlphaBlend.SetLayeredWindowAttributes(Handle, 0, (byte)Num, 2);
        }

        public void AlphaBlendPercent(IntPtr Handle, short Percent)
        {
            AlphaBlend.SetLayeredWindowAttributes(Handle, 0, (byte)Math.Round((double)((((double)Percent) / 100) * 255)), 2);
        }

        public IntPtr FindApplicationWindow([Optional] string WindowClass /* = null */, [Optional] string WindowTitle /* = null */)
        {
            return AlphaBlend.FindWindow(WindowClass, WindowTitle);
        }

        [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int GetWindowLong(IntPtr Handle, int nIndex);

        public void ResetAlphaBlending(IntPtr Handle)
        {
            int num1 = AlphaBlend.GetWindowLong(Handle, -20);
            // The following line has me stumped, in VB, the const WS_EX_LAYERED breaks down to the value 524288
            // Yet on the line below is the same number but increased by one, basically it should (boolean here) num1 and not WS_EX_LAYERED
            AlphaBlend.SetWindowLong(Handle, -20, num1 & -524289);
        }

        [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        private static extern int SetLayeredWindowAttributes(IntPtr Handle, int crKey, byte bAlpha, int dwFlags);

        public void SetupAlphaBlending(IntPtr Handle)
        {
            int num1 = AlphaBlend.GetWindowLong(Handle, -20);
            num1 |= WS_EX_LAYERED;
            AlphaBlend.SetWindowLong(Handle, -20, num1);
        }

        [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int SetWindowLong(IntPtr Handle, int nIndex, int dwNewLong);


        // Fields
        private const short GWL_EXSTYLE = -20;
        private const short LWA_ALPHA = 2;
        private const short LWA_COLORKEY = 1;
        private const int WS_EX_LAYERED = 0x80000;
    }
}
友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

  • 虚心求教解决思路

    虚心求教 本人刚学.net,有好多的问题明白,求大侠帮忙解释一下这个问题,本人不胜感激。 <asp:TreeNode Text="添加" Value="添加"...

  • 【】.NET里有“关于”对话框组件吗

    【求助】.NET里有“关于”对话框组件吗? 小弟最近在用C#写东西,程序已经基本完工了,现在是想弄一个“关于”对话框,就是通常在“帮助...

  • VS2005 控件在winform下只能拖放,不能移动,该怎么解决

    VS2005 控件在winform下只能拖放,不能移动 VS2005 控件在winform下只能拖放,不能移动;在webform下直接拖放都不行.只能从工具箱里...

  • select控件解决方案

    select控件 怎样在select框中显示图片?并且选择一个图片后可以显示在文本框中。请高手指点一下,最好详细一些!有实现的代码更好!!谢谢...

  • devExpress 控件能否将其它文件转换成PDF,该怎么处理

    devExpress 控件能否将其它文件转换成PDF 1..devExpress 控件能否将其它文件转换成PDF(编程的方式自动转换)2.能否在指定位置给现...

  • 初学者求助,关于学习的方法

    菜鸟求助,关于学习的方法 我们刚开始学C#窗体控件,有哪位大虾能给提点学习这方面的建议 ------解决方案-------------------- 找...

  • 关于VS2005添加自定义控件DLL,该怎么解决

    关于VS2005添加自定义控件DLL 我在工具箱里点选择项,浏览dll文件,点确定,但是工具箱里没有显示我选择的控件 ------解决方案-------...

  • fullcalendar怎么绑定数据源

    fullcalendar如何绑定数据源 我做OA的日程安排功能,用的fullcalendar控件,第一次接触各种不会 我想让fullcalendar从绑定的数据源...

  • 求人解答窗口间传递数值有关问题

    求人解答窗口间传递数值问题 我想做的是在Form1里textbox输入字符串或者数字,然后Form2里的 label1 能够显示出来 但是在两个...

  • C# 多项目互相调用

    C# 多项目相互调用 C#的解决方案中有多个项目(WinForm) 各项目都有自定义的组件、控件、公共变量 不同项目之间怎样相互调用、使...

热门推荐: