前阵子做GIS,要实现图层的显示效果,尝试将2个PictureBox(该PictureBox实际是自定义的组件继承自panel,原本想直接重写PictureBox,但是前景和背景支持透明,叠在还是会有问题)叠在一起,将上面的一张图片的BackColor和ForeColor设为Color.Transparent,并不加载任何图片,希望能看见下面一张图片的内容,但始终无法实现,然后得知道Winform默认情况下是不支持透明通道的,所以查阅了相关知识后,尝试继承并重写Winform中控件的一些属性和方法,实现自定义的PictureBox并支持透明通道
现在我们尝试重写PictureBox
我们自定义一个抽象类(不抽象也可以),由于该类无须被实例化所以定义为抽象即可,让该类继承Panel
然后我们重写一下CreateParams属性,建议大家去谷歌一下与该属性相关的内容
重写内容如下
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; // 实现透明样式
return cp;
}
}
然后再考虑重写以下OnPaint事件,设置以下绘制时的相关属性,例如在构造函数中默认前景色和背景色都为透明
由于Onpaint中重写了一些属性,子类继承该类后无法实现刚刚重写的属性,需要自己在Override一遍,所以再Onpaint中再调用一个OnDraw()抽象方法,让子类去重写该抽象方法就可以了
最后我们再新建一个类去继承该类,作为具体的可实例化组件
public abstract class PanelExtend : Panel
{
protected Graphics graphics;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; // 实现透明样式
return cp;
}
}
public PanelExtend()
{
this.BackColor = Color.Transparent;
this.ForeColor = Color.Transparent;
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
}
protected override void OnPaint(PaintEventArgs e)
{
this.graphics = e.Graphics;
this.graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
this.graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
this.graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
this.graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
this.graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
OnDraw();
}
protected abstract void OnDraw();
}
再定义一个类,该类可实例化为具体工具栏组件,继承刚刚重写过Panel的抽象类PictureBoxExtend,并重写抽象类中的OnDraw()方法,该方法描述具体如何绘制
首先获取该组件的长宽,并确定绘制范围为整个组件的大小
然后再是一些具体的绘制要求,此处理应是3个If而不是if else,应该是先判断背景色,有背景色绘制背景色,然后有背景绘制背景,有前景色再绘制前景色,但是一般有背景就不用绘制背景色了,所以避免每次绘制3遍
public class PictureBoxModel : PanelExtend
{
public PictureBoxModel()
{
}
protected override void OnDraw()
{
int width = this.Width;
int height = this.Height;
Rectangle recModel = new Rectangle(0, 0, width, height);
if (this.BackgroundImage != null)
{
this.graphics.DrawImage(this.BackgroundImage, recModel);
}
else if (this.ForeColor != Color.Transparent)
{
this.graphics.Clear(this.ForeColor);
}
else if (this.BackColor != Color.Transparent)
{
this.graphics.Clear(this.BackColor);
}
}
}