How do I draw a transparent rectangle?

一世执手 提交于 2019-12-08 13:35:32

问题


I am nearly there with this ... :)

I have implemented my own double buffer ...

So I create a bitmap:

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

I thought that I might have to manually set the bitmap as transparent.

In my handlers OnPaint method it does this:

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

The problem is that the rectangle is drawing with a black background. So it is obliterating the drawing underneath that is on the bitmap:

How do I draw just the rectangle? What am I missing? I am sorry if this is a dumb question!


回答1:


Painting with transparency is unfortunately only supported in one way: By applying the RGB channels in the strenght of the alpha value.

With alpha = 0 nothing happens.

Other modes are desirable but not supported in GDI+ drawing.

One simple workaround is to turn off antialiasing, draw in a weird color you don't need and then call 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);
}

Of course you can use all DrawXXX methods including FillPath or DrawRectangle.

The result is a green bitmap with a transparent hole in it. Here it is in Paint.Net:

For other modes, that maybe would copy the alpha channel or mix it with the previous value you would have to write routines of your own or find a lib that has it, but I think this should be all you need atm.


Edit by Andrew Truckle

The proposed answer is really good. However, since I was using Teigha.Net as the basis of the application, in the end I went with this code:

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

Notice that I am making use of Region objects. Also, the invalidating is being handled by OdGsDevice _pDevice which is a Teigha object. In my situation this worked fabulously.



来源:https://stackoverflow.com/questions/37646892/how-do-i-draw-a-transparent-rectangle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!