具有透明背景的用户控件

7
我有一个简单的用户控件,实际上只是一个面板。当我在该面板上单击时,会添加一个子用户控件。该子控件只是另一个用户控件,其中我设置width = 150pxheight = 100px,背景颜色为透明,并在中心具有100 x 100像素的文本框。
这个基础结构将来会成为一个节点界面,每个框都会有连接锚点、逻辑按钮之类的东西。
我的问题在于,如果我在面板上点击几次并且添加的框重叠在一起,透明度就不起作用了。
这是一个屏幕截图。
如何解决这个问题?有一个allowTransparency之类的东西吗?
同时,绘制顺序也存在问题,新添加的块总是在其他块后面。
如果您想查看此代码,请告诉我,但我认为对此没有任何相关内容。
此外,如果您知道更好的实现节点图形的方法,请随时告诉我。
编辑
以下代码是我在考虑在StackOverFlow发布问题之前尝试的第一件事。
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
MakeTransparentControls(this);

所以请不要将此视为重复的问题或将代码发布为答案。

问题是用户控件不透明,因此您无法看到其后面的其他控件吗? - John Koerner
这是当前的一个问题,是的。 - Ace
尝试我的方法,它在这篇帖子中运行得非常完美。 - aleksandaril
4个回答

12

在Windows中,窗口会重叠并遮挡其它窗口。使用ControlStyles.SupportsTransparentBackColor并不能解决问题,因为UserControl已经默认开启了该选项。

这个样式标志模拟了窗口透明度,它通过改变窗口绘制方式来实现。首先,它要求父级窗口在窗口内绘制自身以提供背景,然后再在其上绘制自己。所以,将BackColor属性设置为Color.Transparent,您可以期望看到父窗口的像素作为背景。

确实如此。您的用户控件的父级是窗体。它会首先忠实地绘制自己,这会产生左右两侧的灰色边缘。您希望也能看到其他用户控件的像素,但这并不起作用,它只要求父级窗口进行绘制,而没有要求任何重叠的其他控件。当然,这并不是不可能,但它又丑又慢。这篇KB文章展示了一种方法,但更强调“丑陋”的称号。

显然,您可以改进您的UserControl,在Panel左右边缘没有透明区域是没有必要的。所以,将面板的Location属性设置为(0,0),将Dock属性设置为Fill。现在,每个用户控件都只是一个“节点”,您不需要也不想看到任何重叠的其他“节点”的一部分。在节点之间绘制线条需要实现窗体的Paint事件。

如果你真的需要这种透明度,那么你必须以不同的方式来实现。你必须放弃使用每个节点的窗口的想法。一种方法是直接绘制它们。如果你按照正确的顺序绘制,那么你就不会有模拟真正透明度的问题,可以通过分层绘制并且不在需要看到“背景”处绘制来创建真正的透明度。这也会更快,控件是昂贵的。但是你将不得不放弃使用控件的便利性,而要编写代码。像鼠标命中测试这样的事情变得更加复杂。如果文本框并不是一个Label(当然应该是吧?),那它肯定会成为一个障碍。或者使用一个已经放弃使用窗口作为控件的GUI类库,例如WPF。还有别忘了有很多库已经为你做了这件事,连接节点是一种非常常见的用户界面范式,比如Visio。


1
首先,非常感谢这篇详细的文本。我之前尝试过使用WPF和GDI+,但对我来说太复杂了。然后我考虑过使用OpenGL或D3D,但觉得这对于我的目的来说有点过于繁琐。你有没有关于使用WPF或任何库的示例或参考资料可以给我? - Ace
我也考虑过使用能够满足我的需求的库,但任务是要制作自己的节点图。因此,使用库将是我的最后选择,但我可以查看源代码并学习一些东西。 - Ace

8
在您的UserControl的构造函数中尝试以下操作:
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;

4
它已经在我的代码中了。这样,谷歌搜索出现的第一条结果就是我在发布问题之前在网络上搜索到的。^^ - Ace

2
你也可以尝试这个方法:
     public partial class UCTransparent : UserControl
     {

         public UCTransparent()
         {
                InitializeComponent(); 
         }
         protected override CreateParams CreateParams
         {
                get
                {
                       CreateParams cp = base.CreateParams;
                       cp.ExStyle |= 0x20;
                       return cp;
                }
         }

         protected override void OnPaintBackground(PaintEventArgs e)
         {
             base.OnPaintBackground(e);
         }
      }

这实际上有点起作用,但在运行时它对我的控件做了一些疯狂的事情。 - Brandon

0
在我的一个项目中,我不得不为表单上的几乎每个子控件设置透明背景,因此我创建了这个方法:
private void MakeTransparentControls(Control parent)
{
    if (parent.Controls != null && parent.Controls.Count > 0)
    {
        foreach (Control control in parent.Controls)
        {
            if ((control is PictureBox) || (control is Label) || (control is GroupBox) || (control is CheckBox))
                control.BackColor = Color.Transparent;

            if (control.Controls != null && control.Controls.Count > 0)
                MakeTransparentControls(control);
        }
    }
}

在表单的构造函数中,我添加了这些行:
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
MakeTransparentControls(this);

你可以在自己的环境中尝试类似这样的东西。

这是我在搜索这个问题之前谷歌给我的第一件事情,所以它在我的情况下不起作用。 - Ace

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接