0

我几乎就在那里...... :)

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

所以我创建了一个位图:

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

问题是矩形是用黑色背景绘制的。所以它正在抹掉位图上的下面的图形:

缩放窗口

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

4

1 回答 1

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方法,包括FillPathor DrawRectangle

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

例子

对于其他模式,这可能会复制 alpha 通道或将其与以前的值混合,您必须编写自己的例程或找到具有它的库,但我认为这应该是您需要的全部 atm。


安德鲁·特拉克尔编辑

建议的答案非常好。但是,由于我使用 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 _pDeviceTeigha 对象处理。在我的情况下,这非常有效。

于 2016-06-05T21:51:59.633 回答