[英]How do I draw a transparent rectangle?
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: 在我的处理程序的
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);
}
}
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!
抱歉,这是一个愚蠢的问题!
Painting with transparency is unfortunately only supported in one way: By applying the RGB
channels in the strenght of the alpha
value. 不幸的是,仅以一种方式支持使用透明绘画:通过以
alpha
值的强度应用RGB
通道。
With alpha = 0
nothing happens. 当
alpha = 0
没有任何反应 。
Other modes are desirable but not supported in GDI+
drawing. 其他模式是理想的,但
GDI+
图形中不支持。
One simple workaround is to turn off antialiasing, draw in a weird color you don't need and then call MakeTransparent
. 一种简单的解决方法是关闭抗锯齿,绘制不需要的怪异颜色,然后调用
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
. 当然,您可以使用所有
DrawXXX
方法,包括FillPath
或DrawRectangle
。
The result is a green bitmap with a transparent hole in it. 结果是一个绿色的位图,其中有一个透明的孔。 Here it is in Paint.Net:
这是在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. 对于其他模式,可能会复制alpha通道或将其与先前的值混合,则您必须编写自己的例程或找到具有该通道的库,但是我认为这应该是您需要的atm。
Edit by Andrew Truckle 安德鲁·特拉克(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:
但是,由于我使用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);
}
}
Notice that I am making use of Region
objects. 请注意,我正在使用
Region
对象。 Also, the invalidating is being handled by OdGsDevice _pDevice
which is a Teigha object. 同样,无效化也由作为Teigha对象的
OdGsDevice _pDevice
处理。 In my situation this worked fabulously. 在我的情况下,这非常有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.