【问题标题】:How Can I Display Overlapping User Controls Correctly?如何正确显示重叠的用户控件?
【发布时间】:2012-01-31 20:55:46
【问题描述】:

我使用 C#、VisualStudio 2010 并为 Windows 窗体应用程序创建了一个自定义用户控件。除了展示自己并允许自己被拖到别处之外,他们没有太多的行为。但是它们是圆形的,当它们在角落重叠时我无法正确显示它们。

这是我在屏幕上绘制它们的代码:

  public void Circle_Paint(object sender, PaintEventArgs e)
  {
     var g = e.Graphics;

     g.FillEllipse(brushForOuterCircle, 0, 0, Width, Height);
     g.FillEllipse(brushForInnerCircle, lineWidth, lineWidth, Width - 2*lineWidth, Height - 2*lineWidth);

     if(!textLocation.HasValue)
     {
        SizeF m = g.MeasureString(text, textFont);
        textLocation = new PointF((float)((Width - m.Width)/2.0), (float)((Height - m.Height)/2.0));
     }
     g.DrawString(text, textFont, brushForText, textLocation.Value);
  }

这是一个不正确显示的示例,AB 圆圈的东南部不显示,因为 CD 覆盖了该区域。

我应该如何防止这种情况,有没有办法告诉 UserControl “默认情况下你是透明的;我不绘制的任何部分都应该保持这样”?

【问题讨论】:

  • 可能重复:Transparent User Control in .net 当然还有很多很多其他
  • 我知道这个问题,但是在接受的答案中它说:“一个值得注意的不起作用是重叠控件。您只能看到父像素,而不是重叠的像素控制。这是可以修复的,但代码很丑。”所以如果我没有误解它,它就不会回答我的问题。是吗?

标签: c# .net winforms user-controls


【解决方案1】:

尝试:

首先在您的用户控件上设置WS_EX_COMPOSITED 扩展样式,通过覆盖

protected override CreateParams CreateParams
{
   get
   {
     CreateParams cp = base.CreateParams;
     cp.ExStyle |= 0x00000020; // add this
     return cp;
   }
}

之后不要在背景中绘制任何东西

protected override void OnPaintBackground(PaintEventArgs e)
{
   // leave this empty 
}

最后在Paint 中画出你的形状。

应该可以。

【讨论】:

    【解决方案2】:

    试试这个。按照此处的建议创建一个 TransparencyControl:Transparent images with C# WinForms

    using System;
    using System.Windows.Forms;
    using System.Drawing;
    
    public class TransparentControl : Control
    {
        private readonly Timer refresher;
        private Image _image;
    
        public TransparentControl()
        {
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            BackColor = Color.Transparent;
            refresher = new Timer();
            refresher.Tick += TimerOnTick;
            refresher.Interval = 50;
            refresher.Enabled = true;
            refresher.Start();
        }
    
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x20;
                return cp;
            }
        }
    
        protected override void OnMove(EventArgs e)
        {
            RecreateHandle();
        }
    
    
        protected override void OnPaint(PaintEventArgs e)
        {
            if (_image != null)
            {
                e.Graphics.DrawImage(_image, (Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2));
            }
        }
    
        protected override void OnPaintBackground(PaintEventArgs e)
        {
           //Do not paint background
        }
    
        //Hack
        public void Redraw()
        {
            RecreateHandle();
        }
    
        private void TimerOnTick(object source, EventArgs e)
        {
            RecreateHandle();
            refresher.Stop();
        }
    
        public Image Image
        {
            get
            {
                return _image;
            }
            set
            {
                _image = value;
                RecreateHandle();
            }
        }
    }
    

    【讨论】:

    • 谢谢。两个答案基本相同,但我接受另一个答案是更简单的答案。 (我不需要定期刷新)
    【解决方案3】:

    您还应该设置区域,以便它忽略鼠标点击应该是透明的区域。以下面的控件为例。这是一个绘制圆圈的控件。我将 Region 设置为 Ellipse,导致 WinForms 不绘制圆圈外的区域。通过设置区域,它还知道忽略区域外区域的鼠标点击。

    
    using System;
    using System.Drawing.Drawing2D;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace WindowsApplication1
    {
        public class RoundControl : Control
        {
            private readonly GraphicsPath _path;
    
            public RoundControl()
            {
                _path = new GraphicsPath();
            }
    
            protected override void OnResize(EventArgs e)
            {
                _path.Reset();
                _path.AddEllipse(ClientRectangle);
                Invalidate(Region);
                Region = new Region(_path);
                base.OnResize(e);
            }
    
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    _path.Dispose();
                }
                base.Dispose(disposing);
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                using (Pen borderPen = new Pen(ForeColor, 8))
                {
                    e.Graphics.DrawEllipse(borderPen, ClientRectangle);
                }
                base.OnPaint(e);
            }
        }
    }
    

    【讨论】:

    • 太好了,谢谢。 (是否考虑去掉不相关的部分,ResetBorderPen()OnFontChanged()OnForeColorChanged(),这样答案会更清楚?)
    猜你喜欢
    • 2012-12-30
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多