|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
那做企业软件是不是最好用J2EE?.net框架<P> 本文次要先容.Net框架的基础画图手艺。经由过程扼要的先容和示例程序来切磋画图手艺的上风、优势和别的相干注重事项。
简介
侥幸的是当编写一个典范的Windows窗体程序时,窗体和控件的绘制、效果等操纵是不必要出格加以思索的。这是为何呢?由于经由过程利用.Net框架,开辟职员能够拖动一系列的控件到窗体上,并誊写一些复杂的与事务相干联的代码然后在IDE中按F5,一个完完整全的窗体程序就出生了!一切控件都将本人绘制本人,窗体大概控件的巨细和缩放都调剂自若。在这里常常会用到的,且必要引发一点注重的就是控件效果。游戏,自界说图表控件和屏幕回护程序的编写会必要程序员分外撰写用于呼应Paint事务的代码。
本文针对那些Windows窗体开辟职员并有助于他们在使用程序体例过程当中利用复杂的画图手艺。起首,我们会会商一些基础的画图观点。究竟谁在卖力举行绘制操纵?Windows窗体程序是怎样晓得什么时候该举行绘制的?那些绘制代码事实被安排在那里?以后,还将先容图象绘制的两重缓冲区手艺,你将会看到它是如何事情的,如何经由过程一个办法来完成缓存和实践显现的图象间的瓜代。最初,我们将会切磋”智能有效地区”,实践就是仅仅重绘大概扫除使用程序窗体上的有效部分,加速程序的显现和呼应速率。但愿这些观点和手艺可以引诱读者浏览完本文,而且有助于更快和更无效的开辟Windows窗体程序。
Windows窗体利用GDI+图象引擎,在本文中的一切画图代码城市触及利用托管的.Net框架来利用和利用WindowsGDI+图象引擎。
只管本文用于基础的窗体画图操纵,可是它一样供应了疾速的、无效的且有助于进步程序功能的手艺和办法。以是,在通读本文之前倡议读者对.Net框架有个基础的懂得,包含Windows窗体事务处置、复杂的GDI+工具比如Line,Pen和Brush等。熟习VisualBasic.Net大概C#编程言语。
观点
Windows使用程序是本人卖力绘制的,当一个窗体”不洁净”了,也就是说窗体改动了巨细,大概部分被别的程序窗体粉饰,大概从最小化形态恢复时,程序城市收到必要绘制的信息。Windows把这类”不洁净”形态称为”有效的(Invalidated)”形态,我们了解为:必要重绘,当Windows窗体程序必要重绘窗体时它会从Windows动静行列中猎取绘制的信息。这个信息经由.Net框架封装然后传送到窗体的PaintBackground和Paint事务中往,在上述事务中得当的誊写专门用于绘制的代码便可。
复杂的画图示比方下:
usingSystem;
usingSystem.Drawing;
usingSystem.Windows.Forms;
publicclassBasicX:Form{
publicBasicX(){
InitializeComponent();
}
privatevoidBasicX_Paint(objectsender,PaintEventArgse){
Graphicsg=e.Graphics;
Penp=newPen(Color.Red);
intwidth=ClientRectangle.Width;
intheight=ClientRectangle.Height;
g.DrawLine(p,0,0,width,height);
g.DrawLine(p,0,height,width,0);
p.Dispose();
}
privatevoidInitializeComponent(){
this.SetStyle(ControlStyles.ResizeRedraw,true);
this.ClientSize=newSystem.Drawing.Size(300,300);
this.Text="BasicX";
this.Paint+=newPaintEventHandler(this.BasicX_Paint);
}
[System.STAThreadAttribute()]
publicstaticvoidMain(){
Application.Run(newBasicX());
}
}
上述代码分红两个基础的步骤来创立示例程序。起首InitializeComponent办法包括一些属性的设置和附加窗体Paint事务的处置历程。注重,在办法中控件的款式也同时被设置,设置控件的款式也是自界说Windows窗体及控件举动的一种无效路子,比如:控件的"ResizeRedraw"属性唆使当窗体的巨细变更产生今后必要对其完整举行重绘,也就是说重绘时老是必要对全部窗体的客户地区举行重绘。窗体的“客户地区”是指除题目栏和边框的一切窗体地区。能够举行一个风趣的实验,作废该控件的属性然后再运转程序,我们能够很分明的看出为何该属性会被常常的设置,由于窗体调剂巨细后的有效地区基本不会被重绘。
好了,我们必要注重一下BasicX_Paint办法,正如先前所提到的,Paint事务在程序必要重绘时被激活,程序窗体使用Paint事务来卖力回应必要重绘的体系动静,BasicX_Paint办法的挪用必要一个工具sender和一个PaintEventArgs范例的变量,PaintEventArgs类的实例或称之为变量e封装了两个主要的数据,第一个就是窗体的Graphics工具,该工具暗示窗体可绘制的外表也称之为画布用于绘制诸如线、文本和图象等,第二个数据就是ClipRectangle,该Rectangle工具暗示窗体上有效的的矩形局限,大概说就是窗体必要重绘的地区。记着,当窗体的ResizeRedDraw设置后,调剂巨细后该ClipRectangle的巨细实践就即是窗体全部客户地区的巨细,大概是被别的程序窗体粉饰的那部分剪切地区。关于部分剪切地区的用途我们会在智能重绘章节作更具体的论述。
<P> 两重缓冲区画图手艺
两重缓冲区手艺可以使程序的画图加倍疾速战争滑,无效削减绘制时的图象闪灼。该手艺的基础道理是先将图象绘制到内存中的一块画布上,一旦一切的绘制操纵都完成了,再将内存中的画布推到窗体的大概控件的外表将其显现出来。经由过程这类操纵后的程序能利用户感到其加倍疾速和美妙。
上面供应的示例程序可以分析两重缓冲区的观点和完成办法,这个示例所包括的功效已相称完全,且完整能够在实践使用中利用。在该章节前面还会说起该手艺应当共同控件的一些属性设置才干到达更好的效果。
要想明白两重缓冲区画图手艺所带来的优点就请运转SpiderWeb示例程序吧。程序启动并运转后对窗口巨细举行调剂,你会发明利用这类画图算法的效力不高,而且在调剂巨细的过程当中有大批的闪灼呈现。
纵不雅程序的源码你会发明在程序Paint事务激活后是经由过程挪用LineDrawRoutine办法来完成线的绘制的。LineDrawRoutine办法有两个参数,第一个是Graphics工具是用于绘制线条的中央,第二个是画图工具Pen工具用来画线条。代码相称复杂,一个轮回语句,LINEFREQ常量等,程序从窗体外表的左下一向划线到其右上。请注重,程序利用浮点数来盘算在窗体上的绘制地位,如许做的优点就是当窗体的巨细产生变更时地位数据会加倍准确。
privatevoidLineDrawRoutine(Graphicsg,Penp){
floatwidth=ClientRectangle.Width;
floatheight=ClientRectangle.Height;
floatxDelta=width/LINEFREQ;
floatyDelta=height/LINEFREQ;
for(inti=0;i<LINEFREQ;i++){
g.DrawLine(p,0,height-(yDelta*i),xDelta*i,0);
}
}
撰写很复杂的用于呼应Paint事务SpiderWeb_Paint的代码,正如后面所提到的,Graphics工具就是从Paint事务参数PaintEventArgs工具中提掏出来的暗示窗体的绘制外表。这个Graphics工具连同新创立Pen工具一同传送给LineDrawRoutine办法来画出蜘蛛网似的线条,利用完Graphics工具和Pen工具后开释其占用的资本,那末全部绘制操纵就完成了。
privatevoidSpiderWeb_Paint(objectsender,PaintEventArgse){
Graphicsg=e.Graphics;
PenredPen=newPen(Color.Red);
//callourisolateddrawingrouting
LineDrawRoutine(g,redPen);
redPen.Dispose();
g.Dispose();
}
那末究竟作怎样的修改才干使下面的SpiderWeb程序完成复杂的两重缓冲区手艺呢?道理实在相称复杂,就是将应当画到窗体外表的绘制操纵改成先画到内存中的位图上,LineDrawRoutine向这个在内存中埋没的画布实行一样的蜘蛛网绘制操纵,比及绘制终了再经由过程挪用Graphics.DrawImage办法将埋没的画布上内容推到窗体外表来显现出来,最初,再加上一些小的修改一个高功能的画图窗体程序就完成了。
对照上面两重缓冲区画图事务与后面先容的复杂画图事务间的区分:
privatevoidSpiderWeb_DblBuff_Paint(objectsender,PaintEventArgse){
Graphicsg=e.Graphics;
PenbluePen=newPen(Color.Blue);
//createouroffscreenbitmap
BitmaplocalBitmap=newBitmap(ClientRectangle.Width,ClientRectangle.Height);
GraphicsbitmapGraphics=Graphics.FromImage(localBitmap);
//callourisolateddrawingrouting
LineDrawRoutine(bitmapGraphics,bluePen);
//pushourbitmapforwardtothescreen
g.DrawImage(localBitmap,0,0);
bitmapGraphics.Dispose();
bluePen.Dispose();
localBitmap.Dispose();
g.Dispose();
}
下面的示例代码创立了内存位图工具,它的巨细即是窗体的客户地区(就是画图外表)的巨细,经由过程挪用Graphics.FromImage将内存中位图的援用传送给Graphics工具,也就是说前面一切对该Graphics工具的操纵实践上都是对内存中的位图举行操纵的,该操纵在C++中同等于将位图工具的指针复制给Graphics工具,两个工具利用的是统一块内存地点。如今Graphics工具暗示的是屏幕前方的一块画布,而它在两重缓冲区手艺中起到相当主要的感化。一切的线条绘制操纵都已针关于内存中的位图工具,下一步就经由过程挪用DrawImage办法将该位图复制到窗体,蜘蛛网的线条就会立即显现在窗体的绘制外表并且涓滴没有闪灼呈现。
<P> 这一系列的操纵完成后还不是出格无效,由于我们先条件到了,控件的款式也是界说Windows窗体程序举动的一条路子,为了更好的完成两重缓冲区必需设置控件的Opaque属性,这个属性指明窗体是不卖力在背景绘制本人的,换句话说,假如这个属性设置了,那末必需为扫除和重绘操纵增加相干的代码。具有两重缓冲区版本的SpiderWeb程序经由过程以上的设置在每次必要重绘时都体现优秀,窗体外表用其本人的背景致举行扫除,如许就加倍削减了闪灼的呈现。
publicSpiderWeb_DblBuff(){
SetStyle(ControlStyles.ResizeRedraw|ControlStyles.Opaque,true);
}
privatevoidSpiderWeb_DblBuff_Paint(objectsender,PaintEventArgse){
//createouroffscreenbitmap
BitmaplocalBitmap=newBitmap(ClientRectangle.Width,ClientRectangle.Height);
GraphicsbitmapGraphics=Graphics.FromImage(localBitmap);
bitmapGraphics.Clear(BackColor);
//callourisolateddrawingrouting
LineDrawRoutine(bitmapGraphics,bluePen);
}
了局怎样?图象的绘制光滑多了。从内存中将蜘蛛网的线条推到前台以显现出来是完整没有闪灼的,可是我们仍是略微停留一下,先将内存中的位图修整一下再显现出来,能够增加一行代码以便使线条看上往加倍平展。
bitmapGraphics.SmoothingMode=SmoothingMode.AntiAlias;
在将内存中的位图工具赋给Graphics后经由过程安排这行代码,我们在画布上所画的每个线条都利用了反锯齿,使凹凸不屈的线条显得加倍平展。
具有两重缓冲区手艺的且利用AntiAliasing(反锯齿)属性的SpiderWeb_DblBuff示例程序
完成了复杂的两重缓冲区使用后有两个成绩必要向读者分析,.Net中的某些控件比方:Button、PictureBox、Label另有PropertyGrid都已很好的使用了该手艺!这些控件在默许形态下会主动启用两重缓冲区手艺,用户能够经由过程对“DoubleBuffer”属性的设置来就能够完成两重缓冲区手艺。以是,用户若利用PictureBox来绘制蜘蛛网将会更无效率一些,并且也使程序变得加倍复杂了。
我们在这里会商的两重缓冲区手艺既不是完整被优化但也没有甚么太年夜的负面影响。两重缓冲区手艺是削减Windows窗体绘制时闪灼的一条主要路子,可是它也的确损耗很多内存,由于它将会利用双倍的内存空间:使用程序所显现的图象和屏幕前方内存中的图象。每次Paint事务被激活时城市静态的创立位图工具,这类机制会相称泯灭内存。而自带两重缓冲区手艺的控件在利用DoubleBuffer属性后实行起来的优化水平则会更好一些。
利用GDI+的DIB(与设备有关的位图)工具来完成这类画面之外的内存缓冲,自带两重缓冲区机制的控件则能好的使用该位图工具。DIB是底层Win32的工具用于高效的屏幕绘制。一样,值得注重的是GDI+的第一个版本GDI中仅与硬件减速有关和一些复杂功效能够间接利用,因为如许的限定,像反锯齿和半通明等屏幕绘制办法实行起来的速率则相称慢。只管两重缓冲区机制损耗了一些内存可是它的利用无可置疑的加强了程序的实行功能。
<P> 智能重绘,在绘制前必要推敲一下
“智能有效”(智能重绘)就是在表示程序员应当分明仅应对程序中有效的地区举行重绘,对Regions工具所对应的有效地区举行重绘能够进步绘制功能,利用Regions工具你能够仅扫除或绘制控件和窗体的部分地区已取得更好的功能。我们如今就入手下手来看一下BasicClip示例程序,这个程序利用保留在PaintEventArgs工具的ClipRectangle工具,之前我们已说起,不管什么时候当程序的巨细产生变更时Paint事务城市被激活。BasicClip示例程序用红和蓝两种色彩添补剪切的矩形地区,使用分歧的速率调剂窗体的巨细几回今后,你会发明绘制的矩形地区实在就是窗体的有效地区(包含年夜于原始窗体巨细的地区部分和缩少了的地区部分),示例程序的Paint事务代码以下:
privatevoidBasicClip_Paint(objectsender,PaintEventArgse){
Graphicsg=e.Graphics;
//swapcolors
if(currentBrush.Color==Color.Red)
currentBrush.Color=Color.Blue;
else
currentBrush.Color=Color.Red;
g.FillRectangle(currentBrush,e.ClipRectangle);
g.Dispose();
}
该示例程序的独一目标就是演示如何仅针对部分地区举行图形绘制。
BasicClip示例程序中的黑色矩形地区就是暗示窗体的下方和右边的有效地区。
Regions是一种被用来界说Windows窗体大概控件地区的工具,调剂窗体巨细后所取得的Regions就是窗体重绘的最小地区。当程序必要举行绘制的时分仅绘制感乐趣的特别地区,如许绘制更小的地区就会使程序的运转速率更快。
为了更好的演示Regions的用法,请检察TextCliping示例程序。该程序重载了OnPaintBackground和OnPaint办法,间接重载这些办法比侦听事务更能包管代码在别的的绘制操纵之前被挪用,并且关于自界说控件的绘制也加倍无效。为了分明起见,示例程序供应了一个Setup办法,该办法界说了全局的Graphics工具。
privatevoidSetup(){
GraphicsPathtextPath=newGraphicsPath();
textPath.AddString(displayString,FontFamily.GenericSerif,
0,75,newPoint(10,50),newStringFormat());
textRegion=newRegion(textPath);
backgroundBrush=newTextureBrush(newBitmap("CoffeeBeanSmall.jpg"),
WrapMode.Tile);
foregroundBrush=newSolidBrush(Color.Red);
}
下面的Setup办法起首界说一个空的GraphicsPath工具变量textPath,下一步字符串“WindowsForms”的界限被增加到该路径中,环绕这个表面创立Region。如许,一个被绘制在窗体外表的以字符串表面为地区的Region就被创立了。最初,Setup办法创立以材质刷子为背景和以实色刷子为远景来绘制窗体。
protectedoverridevoidOnPaintBackground(PaintEventArgse){
base.OnPaintBackground(e);
GraphicsbgGraphics=e.Graphics;
bgGraphics.SetClip(textRegion,CombineMode.Exclude);
bgGraphics.FillRectangle(backgroundBrush,e.ClipRectangle);
bgGraphics.Dispose();
}
下面界说的OnPaintBackground办法先立即挪用基类办法,这可以包管一切底层绘制的代码都可以被实行。下一步,从PaintEventArgs中取得Graphics工具,再将Graphics工具的剪切地区界说为textRegion工具。经由过程指定CombineMode.Exclude参数,明白不管在那里绘制或如何绘制Graphics工具都不绘制textRegion地区外部。
protectedoverridevoidOnPaint(PaintEventArgse){
base.OnPaint(e);
GraphicsfgGraphics=e.Graphics;
fgGraphics.FillRegion(foregroundBrush,textRegion);
fgGraphics.Dispose();
}
最初,OnPaint事务卖力准确的绘制出字符串。能够很简单的经由过程挪用Graphics的FillRegion办法来完成。经由过程指定的远景刷子foregroundBrush和textRegion且仅是该地区被绘制。了局,Windows窗体程序在运转之前的确“思索”该如何举行绘制。
TextClipping示例程序,经由过程Region界说的WindowsForms字符串。可以使程序在绘制时避开一个地区。
得当的组合利用地区和智能重绘你能够编写出运转速率快且不会引发闪灼的绘制代码,而且比独自利用两重缓冲区绘制还要节俭内存的损耗。
结论
假如你的程序断定要举行绘制操纵,利用几种手艺能够加强绘制功能。确保争夺设置控件属性和得当的Paint事务处置是编写强健程序的入手下手。在衡量好利害后可使用两重缓冲区手艺发生十分“回护目力”的了局。最初,在实践绘制行进行思索究竟哪些客户地区或Region必要被绘制将十分无益。
但愿经由过程这篇文章可以使读者更好的了解关于.net框架的绘制手艺及其使用。不可能天天有学习.net),我一同学说,你应该早就有作品啦。我惶惶然…… |
|