如何绘制透明矩形?

时间:2016-06-05 21:21:04

标签: c# winforms bitmap onpaint graphicspath

我差不多就这样......:)

我已经实现了自己的双缓冲区......

所以我创建了一个位图:

if (_Bitmap != null) _Bitmap.Dispose();
if (_Graphics != null) _Graphics.Dispose();

_Bitmap = new Bitmap(Bounds.Width, Bounds.Height);
_Bitmap.MakeTransparent(Color.Transparent);
_Graphics = Graphics.FromImage(_Bitmap);
_Graphics.FillRectangle(Brushes.Transparent, Bounds);

我认为我可能需要手动将位图设置为透明。

在我的处理程序OnPaint方法中,它执行此操作:

protected override void OnPaint(PaintEventArgs e)
{
    if (_pDevice != null)
    {
        try
        {
            _pDevice.update();
            _Graphics.ReleaseHdc();

            if (_bZoomWindow)
            {
                //_Graphics.DrawRectangle(_selectionPen, _rcRubberBand);
                using (GraphicsPath gp = new GraphicsPath())
                {
                    gp.AddRectangle(_rcRubberBand);
                    gp.Widen(_selectionPen);
                    _Graphics.FillPath(Brushes.WhiteSmoke, gp);
                }
            }

            OdRxDictionary Properties = _graphicsDevice.properties();
            //if (helperDevice.UnderlyingDevice.Properties.Contains("WindowHDC"))
            //    helperDevice.UnderlyingDevice.Properties.AtPut("WindowHDC", new RxVariant((Int32)graphics.GetHdc()));
            if (Properties.ContainsKey("WindowHDC"))
                Properties.putAt("WindowHDC", new OdRxVariantValue(_Graphics.GetHdc().ToInt32())); // hWnd necessary for DirectX device
        }
        catch (System.Exception ex)
        {
            _Graphics.DrawString(ex.ToString(), new Font("Arial", 16), new SolidBrush(Color.Black), new PointF(150.0F, 150.0F));
        }

        e.Graphics.DrawImageUnscaled(_Bitmap, 0, 0);
    }
}

问题是矩形是用黑色背景绘制的。所以它删除了位图下面的绘图:

Zoom window

如何只绘制矩形?我错过了什么?如果这是一个愚蠢的问题,我很抱歉!

1 个答案:

答案 0 :(得分:2)

不幸的是,只有一种方式支持透明度绘画:在RGB值的强度中应用alpha个频道。

alpha = 0 没有

其他模式是可取的,但在GDI+绘图中不受支持。

一个简单的解决方法是关闭抗锯齿,绘制您不需要的奇怪颜色,然后调用MakeTransparent

Bitmap bmp = new Bitmap(244, 244, PixelFormat.Format32bppArgb);
Color funnyColor = Color.FromArgb(255, 123, 45, 67);

using (Graphics g = Graphics.FromImage(bmp))
{
    g.Clear(Color.LawnGreen);
    using (SolidBrush br = new SolidBrush(funnyColor ))
    {
        // no anti-aliased pixels!
        g.SmoothingMode = SmoothingMode.None;
        // draw your stuff..
        g.FillEllipse( br , 14, 14, 88, 88);
    }       
    bmp.MakeTransparent(funnyColor );
    // do what you want..
    bmp.Save(someFileName, ImageFormat.Png);
}

当然,您可以使用所有DrawXXX方法,包括FillPathDrawRectangle

结果是一个带有透明孔的绿色位图。这是在Paint.Net中:

Example

对于其他模式,可能会复制alpha通道或将其与您自己编写自己的例程的前一个值混合或查找具有它的lib,但我认为这应该是您需要的所有内容。< / p>

由Andrew Truckle编辑

建议的答案非常好。但是,由于我使用Teigha.Net作为应用程序的基础,最后我使用了这段代码:

protected override void OnMouseMove(MouseEventArgs e)
{
    if (_bZoomWindowing)
        UpdateRubberBandRectangle(e.Location);

    if (_bPanWindowMode)
        UpdateRubberBandLine(e.Location);

    base.OnMouseMove(e);
}

private void UpdateRubberBandRectangle(Point Location)
{
    // Do we need to erase the old one?
    if (!_rcLastRubberBand.IsEmpty)
    {
        using (Region r = new Region(Rectangle.Inflate(_rcLastRubberBand, 2, 2)))
        {
            r.Exclude(Rectangle.Inflate(_rcLastRubberBand, -2, -2));

            _pDevice.invalidate(new OdGsDCRect(_rcLastRubberBand.Left - 2, _rcLastRubberBand.Right + 2,
                                           _rcLastRubberBand.Top - 2, _rcLastRubberBand.Bottom + 2));
            Invalidate(r);
        }
    }

    // Draw the new one
    if (!_selectionStart.IsEmpty && !_selectionEnd.IsEmpty && _selectionEnd != Location)
    {
        _rcLastRubberBand = _rcRubberBand;

        _selectionEnd = Location;
        _rcRubberBand = GetSelectionRectangle(_selectionStart, _selectionEnd);

        using (Region r = new Region(Rectangle.Inflate(_rcRubberBand, 2, 2)))
        {
            r.Exclude(Rectangle.Inflate(_rcRubberBand, -2, -2));

            _pDevice.invalidate(new OdGsDCRect(_rcRubberBand.Left - 2, _rcRubberBand.Right + 2,
                                           _rcRubberBand.Top - 2, _rcRubberBand.Bottom + 2));
            Invalidate(r);
        }
    }
}

private void UpdateRubberBandLine(Point Location)
{
    // Do we need to erase the last rubber band line? (Rectangle already expanded by 2 pixels)
    if (!_rcLastRubberBandLine.IsEmpty)
    {
        using (Region r = new Region(_rcLastRubberBandLine))
        {
            _pDevice.invalidate(new OdGsDCRect(_rcLastRubberBandLine.Left, _rcLastRubberBandLine.Right,
                                               _rcLastRubberBandLine.Top, _rcLastRubberBandLine.Bottom));
            Invalidate(r);
        }

    }

    // Draw the new one now
    _RubberLineEnd = Location;
    _rcLastRubberBandLine = GetSelectionRectangle(_RubberLineStart, _RubberLineEnd);
    _rcLastRubberBandLine.Inflate(2, 2);
    using (Region r = new Region(_rcLastRubberBandLine))
    {
        _pDevice.invalidate(new OdGsDCRect(_rcLastRubberBandLine.Left, _rcLastRubberBandLine.Right,
                                           _rcLastRubberBandLine.Top, _rcLastRubberBandLine.Bottom));
        Invalidate(r);
    }
}

请注意,我正在使用Region个对象。此外,无效是由OdGsDevice _pDevice处理的,{{1}}是Teigha对象。在我的情况下,这非常有效。