在C#中绘制父级和父级子级的自定义背景

时间:2015-03-13 12:04:10

标签: c# transparency paint custom-painting

我正在尝试使用this tutorial,以便我可以使用透明按钮。它适用于主背景,但它不会吸引其他孩子。如果我使用BringToFront(),那么它就没有其他孩子的绘图。

我已经开始通过将其添加到代码来解决它:

foreach (Control child in Parent.Controls) {
    if(child != this) {
        InvokePaintBackground(child, pea);
        InvokePaint(child, pea);
    }
}

虽然我得到了我想要的一些,但是它位于错误的位置(在左边而不是在它的中间)以及在孩子的绘画事件中绘制的形状也没有出现。

我如何修改以便让所有其他孩子都充分展现透明度?

注意:我并不担心除了其他孩子之外的任何人的痛苦,因为我知道没有任何人,而且还有其他地方很难找到如何递归地获取所有孩子。


感谢C.Evenhuis回答,它现在正在运作。我的实现很简单(只有一个孩子),所以这是我的代码。对于未来的读者,请务必阅读该帖子以获得一个小范围。

using (PaintEventArgs pea = new PaintEventArgs(e.Graphics, rect)) {
    pea.Graphics.SetClip(rect);
    InvokePaintBackground(Parent, pea);
    InvokePaint(Parent, pea);
    foreach (Control child in Parent.Controls) {
        if (child != this) {
            pea.Graphics.ResetTransform();
            pea.Graphics.TranslateTransform(child.Left - Left, child.Top - Top);
            InvokePaintBackground(child, pea);
            InvokePaint(child, pea);
        }
    }
}

2 个答案:

答案 0 :(得分:2)

绘画时,所有控件都假设它们的左上角位于(0,0)坐标处。这是通过在调用Graphics之前将OnPaint对象的视口设置为控件的坐标来实现的。

要绘制其他控件,您必须手动执行此操作:

if (child != this) 
{
    int offsetX = control.Left - Left;
    int offsetY = control.Top - Top;

    // Set the viewport to that of the control
    pevent.Graphics.TranslateTransform(offsetX, offsetY);

    // Translate the clip rectangle to the new coordinate base
    Rectangle clip = pevent.ClipRectangle;
    clip.Offset(-offsetX, -offsetY); // Ugly self-modifying struct
    PaintEventArgs clippedArgs = new PaintEventArgs(pevent.Graphics, clip);
    InvokePaintBackground(control, clippedArgs);
    InvokePaint(control, clippedArgs);
    pevent.Graphics.TranslateTransform(-offsetX, -offsetY)
}

如果底层控件是包含其自身子控件的Panel,则事情会变得复杂一些 - 这些控件不会自动与其父控件一起绘制。如果你也需要支持,我建议向父控件和当前控件下面的silbing控件发送WM_PRINT消息 - 对于兄弟控件,你可以设置PRF_CHILDREN标志让它画画它的后代也是。

目前你正在绘制所有兄弟控件 - 包括当前控件之上的控件。当您到达当前控件时,您可能希望让循环向后移动break。在您开始堆叠多个透明控件之前,这不会是一个真正的问题。

答案 1 :(得分:1)

这不是一个答案,但我必须做一次类似的事情。这就是我所做的:

this.SetStyle(
    ControlStyles.ResizeRedraw | 
    ControlStyles.OptimizedDoubleBuffer | 
    ControlStyles.AllPaintingInWmPaint |
    ControlStyles.SupportsTransparentBackColor |
    ControlStyles.UserPaint, true);

this.BackColor = Color.Transparent;

protected override void OnPaint(PaintEventArgs e)
{
    // TODO: Draw the button here
    base.OnPaint(e);
}

确实吸引孩子,但由于某种原因,它比InvokePaintBackgroundInvokePaint效果更好。我有很多麻烦试图吸引孩子,特别是当孩子们被一些所有者吸引到第三方控制时(我说的是非常奇怪的问题)。我想问一下是否还有其他想法。祝你好运。