gdi+编程10个基本技巧
创建绘图表面
创建绘图表面有两种常用的方法。下面设法得到picturebox的绘图表面。
private void form1_load(object sender, system.eventargs e)
{
//得到picturebox1的绘图表面
graphics g = this.picturebox1.creategraphics();
}
private void picturebox1_paint(object sender, system.windows.forms.painteventargs e)
{
//得到picturebox1的绘图表面
graphics g = e.graphics;
}
可以利用graphics对象绘制出各种图形图案。控件的paint事件和onpaint方法都可以绘图都是好时机。在onpaint方法里绘制图案一定从参数e里面得到graphics属性。下面是两个例子。
protected override void onpaint(painteventargs e)
{
e.graphics.clear(color.white);
float x, y, w, h;
x = this.left+2;
y = this.top+2;
w = this.width-4;
h = this.height-4;
pen pen = new pen(color.red, 2);
e.graphics.drawrectangle(pen, x, y, w, h);
base.onpaint (e);
}
private void pictureboxii_resize(object sender, eventargs e)
{
this.invalidate();
}
private void button1_click(object sender, system.eventargs e)
{
this.pictureboxii1.creategraphics().fillellipse(
brushes.blue, 10, 20, 50, 100);
}
和文本有关的三个类:
fontfamily——定义有着相似的基本设计但在形式上有某些差异的一组字样。无法继承此类。
font——定义特定的文本格式,包括字体、字号和字形属性。无法继承此类。
stringformat——封装文本布局信息(如对齐方式和行距),显示操作(如省略号插入和国家标准 (national) 数字位替换)和 opentype 功能。无法继承此类。
下面的程序显示了一段文字。
private void button2_click(object sender, system.eventargs e)
{
graphics g = this.pictureboxii1.creategraphics();
g.fillrectangle(brushes.white, this.pictureboxii1.clientrectangle);
string s = “aaaaaaaaaaaaaaaaaaaaaaaaaa”;
fontfamily fm = new fontfamily(“ëîìå”);
font f = new font(fm, 20, fontstyle.bold, graphicsunit.point);
rectanglef rectf = new rectanglef(30, 20, 180, 205);
stringformat sf = new stringformat();
solidbrush sbrush = new solidbrush(color.fromargb(255, 0, 0, 255));
sf.linealignment = stringalignment.center;
sf.formatflags = stringformatflags.directionvertical;
g.drawstring(s, f, sbrush, rectf, sf);
}
gdi+的路径——graphicspath类
graphicspath类提供了一系列属性和方法,利用它可以获取路径上的关键点,可以添加直线段、圆等几何元素。可以获得包围矩形,进行拾取测试。这些功能都怎么用,要仔细看一下。
private void button3_click(object sender, system.eventargs e)
{
//绘图表面
graphics g = this.pictureboxii1.creategraphics();
//填充成白色
g.fillrectangle(brushes.white, this.clientrectangle);
//弄一个绘图路径¶
graphicspath gp = new graphicspath();
//添加一些集合图形
gp.addellipse(20, 20, 300, 200);
gp.addpie(50, 100, 300, 100, 45, 200);
gp.addrectangle(new rectangle(100, 30, 100, 80));
//在绘图表面上绘制绘图路径
g.drawpath(pens.blue, gp);
//平移
g.translatetransform(200, 20);
//填充绘图路径¶
g.fillpath(brushes.greenyellow, gp);
gp.dispose();
}
区域——region类
从已有的矩形和路径可以创建region。使用graphics.fillregion方法绘制region。该类指示由矩形和由路径构成的图形形状的内部。无法继承此类。
渐变色填充
需要使用两个刷子:
线性梯度刷子(lineargradientbrush)
路径梯度刷子(pathguadientbrush)
private void button4_click(object sender, system.eventargs e)
{
//绘图表面
graphics g = this.pictureboxii1.creategraphics();
g.fillrectangle(brushes.white, this.pictureboxii1.clientrectangle);
//定义一个线性梯度刷子
lineargradientbrush lgbrush =
new lineargradientbrush(
new point(0, 10),
new point(150, 10),
color.fromargb(255, 0, 0),
color.fromargb(0, 255, 0));
pen pen = new pen(lgbrush);
//用线性笔刷梯度效果的笔绘制一条直线段并填充一个矩形
g.drawline(pen, 10, 130, 500, 130);
g.fillrectangle(lgbrush, 10, 150, 370, 30);
//定义路径并添加一个椭圆
graphicspath gp = new graphicspath();
gp.addellipse(10, 10, 200, 100);
//用该路径定义路径梯度刷子
pathgradientbrush brush =
new pathgradientbrush(gp);
//颜色数组
color[] colors = {
color.fromargb(255, 0, 0),
color.fromargb(100, 100, 100),
color.fromargb(0, 255, 0),
color.fromargb(0, 0, 255)};
//定义颜色渐变比率
float[] r = {0.0f, 0.3f, 0.6f, 1.0f};
colorblend blend = new colorblend();
blend.colors = colors;
blend.positions = r;
brush.interpolationcolors = blend;
//在椭圆外填充一个矩形
g.fillrectangle(brush, 0, 0, 210, 110);
//用添加了椭圆的路径定义第二个路径梯度刷子
graphicspath gp2 = new graphicspath();
gp2.addellipse(300, 0, 200, 100);
pathgradientbrush brush2 = new pathgradientbrush(gp2);
//设置中心点位置和颜色
brush2.centerpoint = new pointf(450, 50);
brush2.centercolor = color.fromargb(0, 255, 0);
//设置边界颜色
color[] color2 = {color.fromargb(255, 0, 0)};
brush2.surroundcolors = color2;
//用第二个梯度刷填充椭圆
g.fillellipse(brush2, 300, 0, 200, 100);
}
gdi+的坐标系统
通用坐标系——用户自定义坐标系。
页面坐标系——虚拟坐标系。
设备坐标系——屏幕坐标系。
当页面坐标系和设备坐标系的单位都是象素时,它们相同。
private void button10_click(object sender, system.eventargs e)
{
graphics g = this.pictureboxii1.creategraphics();
g.clear(color.white);
this.draw(g);
}
private void draw(graphics g)
{
g.drawline(pens.black, 10, 10, 100, 100);
g.drawellipse(pens.black, 50, 50, 200, 100);
g.drawarc(pens.black, 100, 10, 100, 100, 20, 160);
g.drawrectangle(pens.green, 50, 200, 150, 100);
}
private void button5_click(object sender, system.eventargs e)
{
//左移
graphics g = this.pictureboxii1.creategraphics();
g.clear(color.white);
g.translatetransform(-50, 0);
this.draw(g);
}
private void button6_click(object sender, system.eventargs e)
{
//右移
graphics g = this.pictureboxii1.creategraphics();
g.clear(color.white);
g.translatetransform(50, 0);
this.draw(g);
}
private void button7_click(object sender, system.eventargs e)
{
//旋转
graphics g = this.pictureboxii1.creategraphics();
g.clear(color.white);
g.rotatetransform(-30);
this.draw(g);
}
private void button8_click(object sender, system.eventargs e)
{
//放大
graphics g = this.pictureboxii1.creategraphics();
g.clear(color.white);
g.scaletransform(1.2f, 1.2f);
this.draw(g);
}
private void button9_click(object sender, system.eventargs e)
{
//缩小
graphics g = this.pictureboxii1.creategraphics();
g.clear(color.white);
g.scaletransform(0.8f, 0.8f);
this.draw(g);
}
全局坐标——变换对于绘图表面上的每个图元都会产生影响。通常用于设定通用坐标系。
一下程序将原定移动到控件中心,并且y轴正向朝上。
//先画一个圆
graphics g = e.graphics;
g.fillrectangle(brushes.white, this.clientrectangle);
g.drawellipse(pens.black, -100, -100, 200, 200);
//使y轴正向朝上,必须做相对于x轴镜像
//变换矩阵为[1,0,0,-1,0,0]
matrix mat = new matrix(1, 0, 0, -1, 0, 0);
g.transform = mat;
rectangle rect = this.clientrectangle;
int w = rect.width;
int h = rect.height;
g.translatetransform(w/2, -h/2);
//以原点为中心,做一个半径为100的圆
g.drawellipse(pens.red, -100, -100, 200, 200);
g.translatetransform(100, 100);
g.drawellipse(pens.green, -100, -100, 200, 200);
g.scaletransform(2, 2);
g.drawellipse(pens.blue, -100, -100, 200, 200);
局部坐标系——只对某些图形进行变换,而其它图形元素不变。
protected override void onpaint(painteventargs e)
{
graphics g = e.graphics;
//客户区设置为白色
g.fillrectangle(brushes.white, this.clientrectangle);
//y轴朝上
matrix mat = new matrix(1, 0, 0, -1, 0, 0);
g.transform = mat;
//移动坐标原点到窗体中心
rectangle rect = this.clientrectangle;
int w = rect.width;
int h = rect.height;
g.translatetransform(w/2, -h/2);
//在全局坐标下绘制椭圆
g.drawellipse(pens.red, -100, -100, 200, 200);
g.fillrectangle(brushes.black, -108, 0, 8, 8);
g.fillrectangle(brushes.black, 100, 0, 8, 8);
g.fillrectangle(brushes.black, 0, 100, 8, 8);
g.fillrectangle(brushes.black, 0, -108, 8, 8);
//创建一个椭圆然后在局部坐标系中进行变换
graphicspath gp = new graphicspath();
gp.addellipse(-100, -100, 200, 200);
matrix mat2 = new matrix();
//平移
mat2.translate(150, 150);
//旋转
mat2.rotate(30);
gp.transform(mat2);
g.drawpath(pens.blue, gp);
pointf[] p = gp.pathpoints;
g.fillrectangle(brushes.black, p[0].x-2, p[0].y+2, 4, 4);
g.fillrectangle(brushes.black, p[3].x-2, p[3].y+2, 4, 4);
g.fillrectangle(brushes.black, p[6].x-4, p[6].y-4, 4, 4);
g.fillrectangle(brushes.black, p[9].x-4, p[9].y-4, 4, 4);
gp.dispose();
//base.onpaint (e);
}
alpha混合
color.fromargb()的a就是alpha。alpha的取值范围从0到255。0表示完全透明,255完全不透明。
当前色=前景色×alpha/255+背景色×(255-alpha)/255
protected override void onpaint(painteventargs e)
{
graphics g = e.graphics;
//创建一个填充矩形
solidbrush brush = new solidbrush(color.blueviolet);
g.fillrectangle(brush, 180, 70, 200, 150);
//创建一个位图,其中两个位图之间有透明效果
bitmap bm1 = new bitmap(200, 100);
graphics bg1 = graphics.fromimage(bm1);
solidbrush redbrush =
new solidbrush(color.fromargb(210, 255, 0, 0));
solidbrush greenbrush =
new solidbrush(color.fromargb(210, 0, 255, 0));
bg1.fillrectangle(redbrush, 0, 0, 150, 70);
bg1.fillrectangle(greenbrush, 30, 30, 150, 70);
g.drawimage(bm1, 100, 100);
//创建一个位图,其中两个位图之间没有透明效果
bitmap bm2 = new bitmap(200, 100);
graphics bg2 = graphics.fromimage(bm2);
bg2.compositingmode = compositingmode.sourcecopy;
bg2.fillrectangle(redbrush, 0, 0, 150, 170);
bg2.fillrectangle(greenbrush, 30, 30, 150, 70);
g.compositingquality = compositingquality.gammacorrected;
g.drawimage(bm2, 300, 200);
//base.onpaint (e);
}
反走样
protected override void onpaint(painteventargs e)
{
graphics g = e.graphics;
//放大8倍
g.scaletransform(8, 8);
//没有反走样的图形和文字
draw(g);
//设置反走样
g.smoothingmode = smoothingmode.antialias;
//右移40
g.translatetransform(40, 0);
//再绘制就是反走样之后的了
draw(g);
//base.onpaint (e);
}
private void draw(graphics g)
{
//绘制图形和文字
g.drawline(pens.gray, 10, 10, 40, 20);
g.drawellipse(pens.gray, 20, 20, 30, 10);
string s = “反走样测试”;
font font = new font(“宋体”, 5);
solidbrush brush = new solidbrush(color.gray);
g.drawstring(s, font, brush, 10, 40);
}
完了。暂时先总结那么多。以后发现必要的可以再补充。