【问题标题】:Drawing border around control在控件周围绘制边框
【发布时间】:2016-09-11 05:00:26
【问题描述】:

好吧,我想在面板控件周围绘制一个自定义边框,我发现使用它可以轻松实现

ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
                 Color.Indigo, 10, ButtonBorderStyle.Solid,
                 Color.Indigo, 10, ButtonBorderStyle.Solid,
                 Color.Indigo, 10, ButtonBorderStyle.Solid,
                 Color.Indigo, 10, ButtonBorderStyle.Solid);

但是,这个方法和我尝试过的所有其他方法实际上都在面板内绘制了边框,所以当我将一些控件停靠在其中时,控件会隐藏边框。

所以我想知道有没有办法在控件外绘制边框以避免这个问题?

【问题讨论】:

  • 尽管有答案,但您似乎在谈论非客户区绘画,但是,我不知道如何为控件实现它。也许制作自己的控件(作为本机窗口?)是一种方式?

标签: c# winforms


【解决方案1】:

有几种解决方案,但我认为这是最简单的解决方案,您必须确保将面板放置在另一个容器上,以便为它的外边框留出足够的空间。

public class XPanel : Panel {
   public XPanel(){
     BorderWidth = 5;
   }
   Control previousParent;
   public float BorderWidth {get;set;}
   protected override void OnParentChanged(EventArgs e){
     base.OnParentChanged(e);
     if(Parent != previousParent){
       if(Parent != null) Parent.Paint += ParentPaint;
       if(previousParent != null) previousParent.Paint -= ParentPaint;
       previousParent = Parent;
     }
   }
   private void ParentPaint(object sender, PaintEventArgs e){
     using(Pen p = new Pen(Color.Blue, BorderWidth))
     using(var gp = new GraphicsPath())
     {
       float halfPenWidth = BorderWidth / 2;
       var borderRect = new RectangleF(Left - halfPenWidth, Top - halfPenWidth,
                                      Width + BorderWidth, Height + BorderWidth);
       gp.AddRectangle(borderRect);
       e.Graphics.DrawPath(p,gp);
     }
   }
   protected override void OnSizeChanged(EventArgs e){
      base.OnSizeChanged(e);
      if(Parent!=null) Parent.Invalidate();
   }
   protected override void OnLocationChanged(EventArgs e){
      base.OnLocationChanged(e);
      if(Parent != null) Parent.Invalidate();
   }
}

请注意,边框绘制代码现在必须在面板的父级上绘制,您必须相应地调整边框 Rectangle(它当然比在面板内绘制的边框大)。

还要注意,由于在父级上绘制,当您的面板的大小或位置发生变化时,我们需要使父级无效才能正确重绘。 Invalidate() 方法可以接受 Rectangle 以使该矩形无效,您可以计算要绘制的 border Rectangle 并传入该 Invalidate 方法以提高绘制性能很少(主要有助于防止闪烁)。

【讨论】:

  • 好吧,为什么它没有在我的父面板后面对齐?
  • 还有Control previousParent;有什么用
  • @RuneS 它用于在父级更改为新父级时引用前一个父级,我们需要保留该引用以将Paint 事件处理程序与该忘记/旧父级分离
  • 好的,但是我知道为什么这个方法没有对齐我的控件后面的边框,也没有在调整大小时更新
  • @RuneS 我更新了代码以支持调整大小和更改位置。 does not align the border behind my control 是什么意思?
【解决方案2】:

Panel 控件上有一个 BorderStyle 属性。不过,您的选择有限。

您正在绘制的边框丢失的原因是因为您的绘图位于面板空间内。

你有两种选择可以得到你想要的。

1) 获得所需内容的最简单方法是堆叠面板。让后面的那个有任何你想要的边框的背景颜色。然后在该面板内放置另一个面板,其边框为您希望边框的任何宽度。 (如果你想要一个 4 像素的边框,“内部”/“顶部”面板的宽度和高度将小 8 像素)。

2) 向 Panel 对象添加功能以按照您的方式绘制边框。但这将是一项非常艰巨的工作。

【讨论】:

    【解决方案3】:

    肮脏而简单的解决方案。基于 krillgar 和 King King 的回答。

    你可以创建自己的Panel,它将持有另一个Panelinside(在构造函数中创建它)并将所有ControlAdded/ControlRemoved转发给它,同时完美定位它里面。这样您就可以像现在一样继续绘制边框。

    【讨论】:

      【解决方案4】:

      与其因为无法在您的区域之外进行绘制而采用丑陋的解决方法,不如将东西保留在您的边界内;所以不要使用停靠,使用锚。

      例如:

      Controls.Add(mScrollBar);
      int borderSize = 1; // some border size
      
      mScrollBar.SetBounds(
         Right - mScrollBar.Width - borderSize, // x; from the right, the width and the border
         borderSize,                            // y; from the top, just the border
         mScrollBar.Width,                      // width can stay the same
         Height - borderSize * 2                // height minus two borders
      );
      
      mScrollBar.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right;
      

      【讨论】:

        猜你喜欢
        • 2011-01-12
        • 2017-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-10
        • 2020-10-15
        • 1970-01-01
        相关资源
        最近更新 更多