在 C# 中绘制 parent 和 parent children 的自定义背景

Painting custom background of parent and parent children in C#

我正在尝试使用 this tutorial 这样我就可以拥有一个透明按钮。它适用于主背景,但不会覆盖其他 children。如果我使用 BringToFront(),那么其他 child 的绘图就不会出现在它应该出现的位置。

我已经开始通过将此添加到代码中来绕过它:

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

虽然我得到了 一些 我想要的东西,但它在错误的位置(在左边而不是在它应该在的中间)和绘制的形状child 的绘画事件也没有出现。

我该如何修改才能拥有所有其他 children 以及完全透明的幻觉?

注意: 除了其他 children,我不担心任何人的痛苦,因为我知道没有,还有很多其他地方可以找到如何递归地获取所有 children。


感谢 的回答,它现在可以使用了。我的实现很简单(只有一个其他child),所以这是我的代码。对于未来的读者,请务必阅读 post 以获得完整的范围。

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);
        }
    }
}

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

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);
}

它确实 将 children 拉到后面,但由于某些原因它比 InvokePaintBackgroundInvokePaint 效果更好。我在尝试绘制 children 时遇到了很多麻烦,尤其是当 children 是一些所有者绘制的第 3 方控件时(我说的是非常奇怪的问题)。我会最喜欢提问,看看是否还有其他想法。祝你好运。

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

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

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 消息 - 对于同级控件,您可以设置 PRF_CHILDREN 标志让它绘制它的后代也是。

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