如何绘制透明矩形?
How do I draw a transparent rectangle?
我快到了......:)
我已经实现了自己的双缓冲区...
所以我创建了一个位图:
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);
}
}
问题是矩形是用黑色背景绘制的。所以它正在抹去位图下面的绘图:
如何只绘制矩形?我错过了什么?如果这是一个愚蠢的问题,我很抱歉!
使用 透明度 绘画仅支持一种方式:通过在 alpha
值的强度下应用 RGB
通道。
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
方法,包括 FillPath
或 DrawRectangle
。
结果是一个带有透明孔的绿色位图。这是在 Paint.Net:
对于其他模式,这可能会复制 alpha 通道或将其与以前的值混合,您将不得不编写自己的例程或找到具有它的库,但我认为这应该是您所需要的 atm .
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
个对象。此外,失效由 Teigha 对象 OdGsDevice _pDevice
处理。在我的情况下,这非常有效。
我快到了......:)
我已经实现了自己的双缓冲区...
所以我创建了一个位图:
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);
}
}
问题是矩形是用黑色背景绘制的。所以它正在抹去位图下面的绘图:
如何只绘制矩形?我错过了什么?如果这是一个愚蠢的问题,我很抱歉!
使用 透明度 绘画仅支持一种方式:通过在 alpha
值的强度下应用 RGB
通道。
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
方法,包括 FillPath
或 DrawRectangle
。
结果是一个带有透明孔的绿色位图。这是在 Paint.Net:
对于其他模式,这可能会复制 alpha 通道或将其与以前的值混合,您将不得不编写自己的例程或找到具有它的库,但我认为这应该是您所需要的 atm .
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
个对象。此外,失效由 Teigha 对象 OdGsDevice _pDevice
处理。在我的情况下,这非常有效。