zoukankan      html  css  js  c++  java
  • 如何使控件背景色支持TransparentKey(at Win2k/WinXP 32bit Color Desktop)

    问题:
        在Window 2000和WindowsXP 32bit Color桌面下,自己写了Control,放到DoubleBuffered为True的Form上设置背景颜色(BackColor)为Form的TransparentKey相同的颜色后,发现没有透下去,下面是Demo代码:

    控件代码:
     1    public class MyControl : Control
     2    {
     3        protected override void OnPaint(PaintEventArgs e)
     4        {
     5            // Drawing border
     6            if (Application.RenderWithVisualStyles)
     7            {
     8                new VisualStyleRenderer(VisualStyleElement.TextBox.TextEdit.Hot).DrawEdge(e.Graphics,
     9                    this.ClientRectangle,
    10                    Edges.Left | Edges.Top | Edges.Right | Edges.Bottom,
    11                    EdgeStyle.Raised,
    12                    EdgeEffects.Mono);
    13            }

    14            else
    15            {
    16                ControlPaint.DrawBorder3D(e.Graphics, this.ClientRectangle);
    17            }

    18
    19            base.OnPaint(e);
    20
    21            // Drawing demo string/
    22            using (StringFormat sf = new StringFormat())
    23            {
    24                sf.Alignment = StringAlignment.Center;
    25                e.Graphics.DrawString("This is Test Control"this.Font, Brushes.Black, this.ClientRectangle, sf);
    26            }

    27        }

    28
    29        protected override void OnPaintBackground(PaintEventArgs pevent)
    30        {
    31            base.OnPaintBackground(pevent);
    32
    33            //Here I want fill some shape at Background, for example fill ellipse at half-top client.
    34            using (Brush brush = new SolidBrush(Color.Red))
    35            {
    36                pevent.Graphics.FillEllipse(brush, new Rectangle(00this.Width, this.Height / 2));
    37            }

    38        }

    39    }
    下图是在Window XP 32bit Color桌面下的运行效果:

    显然这里没有透下去,但是.NET自带Control都可以透下去!

    找了很久也没有找到问题所在,只好祭出Reflector,看MS的内部实现了,从
    OnPaintBackground(PaintEventArgs pevent)->
    PaintBackground(PaintEventArgs e, Rectangle rectangle)->
    PaintBackground(PaintEventArgs e, Rectangle rectangle, Color backColor, Point scrollOffset)->
    PaintBackColor(PaintEventArgs e, Rectangle rectangle, Color backColor):
     1private static void PaintBackColor(PaintEventArgs e, Rectangle rectangle, Color backColor) {
     2            // Common case of just painting the background.  For this, we 
     3            // use GDI because it is faster for simple things than creating
     4            // a graphics object, brush, etc.  Also, we may be able to
     5            // use a system brush, avoiding the brush create altogether.
     6            // 
     7            Color color = backColor;
     8 
     9            // we use GDI to paint in most cases using WindowsGraphics 
    10            bool painted = false;
    11            if (color.A == 255
    12                using( WindowsGraphics wg = WindowsGraphics.FromGraphics( e.Graphics ) ) {
    13                    color = wg.GetNearestColor(color);
    14
    15                    using (WindowsBrush brush = new WindowsSolidBrush(wg.DeviceContext, color))  
    16                        wg.FillRectangle(brush, rectangle);
    17                    }
     
    18                }
     
    19
    20                painted = true
    21                /*
    22                if (DisplayInformation.BitsPerPixel > 8) {
    23                    NativeMethods.RECT r = new NativeMethods.RECT(rectangle.X, rectangle.Y, rectangle.Right, rectangle.Bottom);
    24                    SafeNativeMethods.FillRect(new HandleRef(e, e.HDC), ref r, new HandleRef(this, BackColorBrush)); 
    25                    painted = true;
    26                }*/
     
    27            }
     
    28
    29            if (!painted) 
    30                // don't paint anything from 100% transparent background
    31                //
    32                if (color.A > 0{
    33                    // Color has some transparency or we have no HDC, so we must 
    34                    // fall back to using GDI+.
    35                    // 
    36                    using (Brush brush = new SolidBrush(color)) 
    37                        e.Graphics.FillRectangle(brush, rectangle);
    38                    }
     
    39                }

    40            }

    41        }


    发现MS Code对这里的注释,只说这里使用GDI画的,在12行,这里使用的WindowsGraphics就是对GDI的封装。
    所以要想实现和MS Control一样,任何环境都支持TransparentKey,这里的背景只能使用GDI来画,修改MyControl代码如下就可以了:

     1    public class MyControl : Control
     2    {
     3        protected override void OnPaint(PaintEventArgs e)
     4        {
     5            // Drawing border
     6            if (Application.RenderWithVisualStyles)
     7            {
     8                new VisualStyleRenderer(VisualStyleElement.TextBox.TextEdit.Hot).DrawEdge(e.Graphics,
     9                    this.ClientRectangle,
    10                    Edges.Left | Edges.Top | Edges.Right | Edges.Bottom,
    11                    EdgeStyle.Raised,
    12                    EdgeEffects.Mono);
    13            }

    14            else
    15            {
    16                ControlPaint.DrawBorder3D(e.Graphics, this.ClientRectangle);
    17            }

    18
    19            base.OnPaint(e);
    20
    21            // Drawing demo string/
    22            using (StringFormat sf = new StringFormat())
    23            {
    24                sf.Alignment = StringAlignment.Center;
    25                e.Graphics.DrawString("This is Test Control"this.Font, Brushes.Black, this.ClientRectangle, sf);
    26            }

    27        }

    28
    29        protected override void OnPaintBackground(PaintEventArgs pevent)
    30        {
    31            base.OnPaintBackground(pevent);
    32
    33            //Here I want fill some shape at Background, for example fill ellipse at half-top client.
    34            //using (Brush brush = new SolidBrush(Color.Red))
    35            //{
    36            //    pevent.Graphics.FillEllipse(brush, new Rectangle(0, 0, this.Width, this.Height / 2));
    37            //}
    38            IntPtr hdc = IntPtr.Zero;
    39            try
    40            {
    41                hdc = pevent.Graphics.GetHdc();
    42                if (hdc != IntPtr.Zero)
    43                {
    44                    IntPtr hBrush = CreateSolidBrush(ColorTranslator.ToWin32(Color.Red));
    45                    if (hBrush != IntPtr.Zero)
    46                    {
    47                        IntPtr oldBrush = SelectObject(hdc, hBrush);
    48                        Ellipse(hdc, 00this.Right, this.Height / 2);
    49                        SelectObject(hdc, oldBrush);
    50
    51                        DeleteObject(hBrush);
    52                        hBrush = IntPtr.Zero;
    53                    }

    54                }

    55            }

    56            finally
    57            {
    58                if (hdc != IntPtr.Zero)
    59                {
    60                    pevent.Graphics.ReleaseHdc(hdc);
    61                }

    62            }

    63        }

    64
    65        [DllImport("gdi32.dll")]
    66        [return: MarshalAs(UnmanagedType.Bool)]
    67        private static extern bool Ellipse(IntPtr hdc, int leftRect, int topRect, int rightRect, int bottomRect);
    68
    69        [DllImport("gdi32.dll")]
    70        private static extern IntPtr SelectObject(IntPtr hDC, IntPtr gdiObject);
    71
    72        [DllImport("gdi32.dll")]
    73        private static extern IntPtr CreateSolidBrush(int color);
    74
    75        [DllImport("gdi32.dll")]
    76        [return: MarshalAs(UnmanagedType.Bool)]
    77        private static extern bool DeleteObject(IntPtr gdiObject);
    78    }

    To be the apostrophe which changed “Impossible” into “I’m possible”
    ----------------------------------------------------
    WinkingZhang's Blog (http://winkingzhang.cnblogs.com)
    GCDN(http://gcdn.grapecity.com/cs)
  • 相关阅读:
    ActiveMQ的学习(四)(消息投递方式+死信队列+重发策略)
    ActiveMQ的学习(三)(ActiveMQ的消息事务和消息的确认机制)
    ActiveMQ的学习(二)(ActiveMQ的持久化)
    ActiveMQ的学习(一)(ActiveMQ和JMS的介绍)
    redis总结(持续更新)
    easyUI--搜索条件控件的处理
    bootstrap的下载和引用
    springMVC总结
    easyUi--datagrid的一些处理
    测试工作一
  • 原文地址:https://www.cnblogs.com/winkingzhang/p/1015207.html
Copyright © 2011-2022 走看看