3

我正在尝试使用本教程,以便我可以拥有一个透明按钮。它适用于主要背景,但不会覆盖其他孩子。如果我使用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);
        }
    }
}
4

2 回答 2

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——这些子控件不会与它们的父控件一起自动绘制。如果您也需要支持,我建议向WM_PRINT父控件和当前控件下方的 silbing 控件发送消息 - 对于兄弟控件,您可以设置PRF_CHILDREN标志以使其也绘制其后代。

此外,目前您正在绘制所有同级控件 - 包括当前控件上方的那些。break当您到达当前控件时,您可能希望让循环倒退。在您开始堆叠多个透明控件之前,这不会是一个真正的问题。

于 2015-03-13T12:45:28.440 回答
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);
}

它不会孩子们拉到后面,但出于某种原因InvokePaintBackground,它的效果要好得多。InvokePaint我在尝试绘制孩子时遇到了很多麻烦,尤其是当孩子是一些所有者绘制的第 3 方控件时(我说的是非常奇怪的问题)。我会喜欢提问,看看是否还有其他想法。祝你好运。

于 2015-03-13T12:15:56.143 回答