绘图控件与透明背景

时间:2012-06-30 17:59:28

标签: compact-framework .net-cf-3.5

我一直在尝试显示一个透明边框作为控件背景的图像。

不幸的是,透明区域在父窗体中创建了一个洞,如下所示:

在上图中,表格有一个红色背景,我希望在透明区域内看到我的控制。

我使用的代码如下:

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        if (this.Image != null)
        {
            Graphics g = Graphics.FromImage(this.Image);

            ImageAttributes attr = new ImageAttributes();

            //set the transparency based on the top left pixel
            attr.SetColorKey((this.Image as Bitmap).GetPixel(0, 0), (this.Image as Bitmap).GetPixel(0, 0));

            //draw the image using the image attributes.
            Rectangle dstRect = new Rectangle(0, 0, this.Image.Width, this.Image.Height);

            e.Graphics.DrawImage(this.Image, dstRect, 0, 0, this.Image.Width, this.Image.Height,
                GraphicsUnit.Pixel, attr);
        }
        else
        {
            base.OnPaint(e);
        }
    }

    protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
    {
        //base.OnPaintBackground(e);
    }

此类继承自PictureBox,因为我需要一个实现OnMouseMove和OnMouseUp事件的控件。

我一直在研究大部分时间而没有成功测试出不同的想法,但不幸的是,大部分只能在完整的框架上工作而不是.Net CF.

非常感谢任何想法。

1 个答案:

答案 0 :(得分:6)

啊CF透明度的乐趣啊。我可以继续谈论它(并且有in my blog和我很久以前做过的Project Resistance code

要点就是这个。子控件必须绘制它的区域,但首先它必须回调它的父级(在你的情况下为Form)并告诉它除了在孩子的剪辑区域之外的任何地方重绘它的背景图像然后在它之上绘制它自己。如果这听起来有点令人困惑,那是因为它是。

例如,如果你看Project Resistance,一个View(它只是一个Control)会绘制一个电阻和波段。它位于一个具有图像背景的表格中,该背景需要“透过”电阻的透明区域:

enter image description here

所以在电阻器的绘图代码中它是这样做的:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    try
    {
        RECT rect = new RECT(this.Bounds);

        // draw the blank
        Infrastructure.GraphicTools.DrawTransparentBitmap(e.Graphics, m_blankImage, Bounds, 
              new Rectangle(0, 0, m_blankImage.Width, m_blankImage.Height));

        if (m_bandsImage != null)
        {
            // draw the bands
            Infrastructure.GraphicTools.DrawTransparentBitmap(e.Graphics, m_bandsImage, Bounds, 
                 new Rectangle(0, 0, m_bandsImage.Width, m_bandsImage.Height));
        }
    }
    finally
    {
    }

    if (!Controller.TouchMode)
    {
        // TODO: draw in the selection arrow
        // Controller.SelectedBand
    }
}

这很简单。关键是它调用它的基础OnPaint,它执行此操作:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    // this assumes we're in a workspace, on MainForm (the whole Parent.Parent thing)
    IBackgroundPaintProvider bgPaintProvider = Parent.Parent as IBackgroundPaintProvider;
    if (bgPaintProvider != null)
    {
        Rectangle rcPaint = e.ClipRectangle;
        // use the parent, since it's the workspace position in the Form we want, 
        // not our position in the workspace
        rcPaint.Offset(Parent.Left, Parent.Top);
        bgPaintProvider.PaintBackground(e.Graphics, e.ClipRectangle, rcPaint);
    }
}

你可以看到它正在调用包含Form的PaintBackground(在这种情况下它是Parent.Parent,因为Control实际上是在一个名为Workspace的容器中 - 你不需要在你的情况下走两次) 。这会将您当前看到的区域中的背景图像绘制为“洞”

public void PaintBackground(Graphics g, Rectangle targetRect, Rectangle sourceRect)
{
    g.DrawImage(m_bmBuffer, targetRect, sourceRect, GraphicsUnit.Pixel);
}