.net 窗话柄现比较完美玻璃透明效果

.net 窗口实现比较完美玻璃透明效果

为了实现.net 下窗口玻璃透明效果,在网上找了很多例子,废了一番功夫,但是还是没有找到完美的例子。CodeProject上有一些例子,有一篇好像是国人写的,不过还是不够完美。

在win7以上系统实现玻璃效果,主要通过DwmExtendFrameIntoClientArea函数实现。当然,这个函数是操作系统API。不过这个在.net 窗口里使用的话,会出现一些问题,就是窗口里控件(比如按钮)的字体会变成透明色,会和玻璃和桌面背景混合。反正就是具备了一定的透明度,这样效果不是很好。有一种不是很完美的解决办法,就是利用Dwm函数绘制文本,或者使用C++里面的TextOut,但是感觉都不完美。

后来一直在找方法,研究了.net下窗口的工作原理,得出结论是无法完美实现透明效果。

无聊之中,不断测试了各种情况下,TransparencyKey各种颜色效果,包括不设置TransparencyKey。结果突然发现,在一种颜色下,控件上的文本不再变透明了!这种颜色是一种淡蓝色。因为之前设置的窗口背景色和TransparencyKey都是同一种颜色,而且要么是黑色,要么是白色,要么是灰色,而淡蓝色可以完美实现玻璃效果,我猜测,只要不是灰度色,那么都可以实现完美玻璃效果。经测试,证明了这一点。

为了完美实现玻璃透明效果和玻璃处点击可以拖动窗口的效果,有以下要点:

1、在适当的地方调用DwmExtendFrameIntoClientArea,比如在Load函数处。如果要实现全玻璃,可以让页距4个边都为-1;

2、TranseparencyKey要设置一种颜色,窗口背景色也设置成同一种颜色,并且颜色都为非灰度颜色,换句话说,不能是黑白电视机屏幕的颜色。

3、处理WndProc函数,让客户处的点击都视为拖动,非客户区让原有WndProc函数继续处理(不然没法拖动窗口大小)。

4、不必在WndProc函数修改窗口客户端大小。

5、不必使用Dwm 函数绘制带发光字体的文本。

下面是代码,部分代码和效果:

            Color k = Color.Brown;
            this.BackColor = k;
            this.TransparencyKey = k;
            SetStyle(ControlStyles.ResizeRedraw, true);
            DoubleBuffered = true;
            CheckGlassEnabled();

            dwmMargins.cyBottomHeight = -1;
            dwmMargins.cyTopHeight = -1;
            dwmMargins.cxLeftWidth = -1;
            dwmMargins.cxRightWidth = -1;

            //dwmMargins.cyBottomHeight = this.ClientSize.Height - listView1.Bottom;
            //dwmMargins.cyTopHeight = listView1.Top;
            //dwmMargins.cxLeftWidth = listView1.Left;
            //dwmMargins.cxRightWidth =listView1.Left;
            Dwm.DwmExtendFrameIntoClientArea(this.Handle, ref dwmMargins);


        protected override void WndProc(ref Message m)
        {
            int HTCAPTION = 2;
            int WM_NCCALCSIZE = 0x83;
            int WM_NCHITTEST = 0x84;
            IntPtr result;

            if (m.Msg == WM_NCHITTEST && (int)m.Result == 0)
            {
                m.Result = HitTestNCA(m.HWnd, m.WParam, m.LParam);
                //m.Result = new IntPtr(HTCAPTION);
                if (m.Result.ToInt32() != HTCAPTION)
                    base.WndProc(ref m);
            }
            else base.WndProc(ref m);
        }

        private IntPtr HitTestNCA(IntPtr hwnd, IntPtr wparam, IntPtr lparam)
        {
            int HTTRANSPARENT = -1;
            int HTNOWHERE = 0;
            int HTCLIENT = 1;
            int HTCAPTION = 2;
            int HTGROWBOX = 4;
            int HTSIZE = HTGROWBOX;
            int HTMINBUTTON = 8;
            int HTMAXBUTTON = 9;
            int HTLEFT = 10;
            int HTRIGHT = 11;
            int HTTOP = 12;
            int HTTOPLEFT = 13;
            int HTTOPRIGHT = 14;
            int HTBOTTOM = 15;
            int HTBOTTOMLEFT = 16;
            int HTBOTTOMRIGHT = 17;
            int HTREDUCE = HTMINBUTTON;
            int HTZOOM = HTMAXBUTTON;
            int HTSIZEFIRST = HTLEFT;
            int HTSIZELAST = HTBOTTOMRIGHT;

            Point p = new Point(LoWord((int)lparam), HiWord((int)lparam));

            Rectangle client = RectangleToScreen(ClientRectangle);
            if (client.Contains(p))
                return new IntPtr(HTCAPTION);
            return new IntPtr(HTNOWHERE);
        }

        public static int LoWord(int dwValue)
        {
            return dwValue & 0xFFFF;
        }
        public static int HiWord(int dwValue)
        {
            return (dwValue >> 16) & 0xFFFF;
        }

.net 窗话柄现比较完美玻璃透明效果

.net 窗话柄现比较完美玻璃透明效果