鲜为人知的setstyle方法可以让你控制重绘一个窗体的方式。
by ken getz
注:ken getz在orlando的vslive!上同brian randell一起举办了一个主题为“build a rich client app with visual studio .net”的研讨会。本篇技巧选自该研讨会的资料。
运用gdi+和windows窗体,我们可以很容易地创建一个渐变色(gradient)来填充一个区域。运用.net framework提供的简单的方法,你可以创建linear gradients(线型渐变填充)或path gradients(路径渐变填充)。然而,真正的问题是这些复杂的背景图形是资源密集型(resource-intensive)的。最近,我正在做一个模拟的时钟演示程序,用一个渐变色来填充钟面。每一秒,当时钟重绘它的钟面来显示时钟指针的正确位置时,它也重绘了整个背景渐变色。即使在一台很快的机器上,这种方法也并不很好。我将向你介绍setstyle方法,它可以让你指定如何、何时来重绘你的窗体。
首先,用下面的代码做试验,你可以从中得到一些着色变换的乐趣。修改一个新窗体的paint事件使它包含该代码: private sub frmmain_paint( _ byval sender as object, _ byval e as painteventargs) _ handles mybase.paint dim path as new graphicspath() dim pt as new pointf() dim rct as rectangle = me.clientrectangle path.addrectangle(rct) dim pgb as new pathgradientbrush(path) pt = new pointf( _ ctype(me.clientsize.width / 2, single), _ ctype(me.clientsize.height / 2, single)) pgb.centerpoint = pt dim colors() as color = _ {color.red, color.orange, color.yellow, _ color.green, _ color.blue, color.indigo, color.violet} dim positions() as single = _ {0.0, 0.1, 0.2, 0.4, 0.6, 0.8, 1} dim cb as colorblend = new colorblend() cb.colors = colors cb.positions = positions pgb.interpolationcolors = cb e.graphics.fillrectangle(pgb, rct) dim f as new stringformat() f.alignment = stringalignment.center e.graphics.drawstring( _ date.now.tolongtimestring, _ new font("tahoma", 13), brushes.white, pt, f)end sub
这里有很多代码,但它们很简单。该代码创建了一个新的graphicspath对象,给graphicspath添加一个填充了整个窗体的矩形,然后根据graphicspath创建一个gradientbrush对象。该代码为渐变色设置了中心点,创建了要用的渐变颜色数组,创建位置数组(颜色渐变的整个范围),创建一个新的缺省的colorblend对象,设置渐变色的属性,然后用渐变色填充矩形。
另外,给窗体添加一个timer控件,激活它,将时间间隔设置为500毫秒,将下面的代码添加到timer事件中: private sub timer1_tick( _ byval sender as system.object, _ byval e as system.eventargs) _ handles timer1.tick me.invalidate()end sub
运行该程序,你就可以得到一个有颜色背景的漂亮的时钟了。有问题吗?是的,通常会有渐变色重绘的问题。而且画面闪动得很厉害,你不得不警惕它对视力的损伤。另外,当你尝试调整窗体大小时,你会发现,在你强迫窗体重绘前(将另一个窗体拖到该窗体上,然后移开先前的窗体。我不建议将这种方法推荐给最终用户),渐变色不会自己进行调整。
解决方法很简单:窗体的setstyle方法可以让你设置不同的值,这些值影响窗体重绘的方式。你可以把resizedraw样式(style)设置为true,这样当你调整窗体的大小时,窗体就自动地重绘了。你也可以把doublebuffer样式设置成true,这样当每次重绘窗体的某一部分时,就不会完全重绘整个窗体了。该选项占用额外的内存,这是因为在.net运行时,除了实际的窗体本身占用内存外,窗体图片的一个副本也必须存储在内存中,但这么做的结果是很值得的。(要运用doublebuffer选项,你也必须将allpaintinginwmpaint和userpaint样式设置成true。)在你的窗体的load事件中添加下面的代码,你就可以完成该设置了: me.setstyle(controlstyles.resizeredraw, true)me.setstyle(controlstyles.allpaintinginwmpaint _ or controlstyles.userpaint or _ controlstyles.doublebuffer, true)
重新运行该演示程序,你会看到你就得到了一个大小调整了的、吸引人的、填充了渐变色的数字时钟。关于这个有用的方法的更多的资料,请查看.net framework帮助文件中的setstyle方法。
关于作者:
ken getz是mcw technologies公司的一位高级顾问,他的时间主要用来编程、写书和培训。ken已经编写了许多技术书籍了,包括与paul d. sheriff合作的asp.net developer’s jumpstart。他的联系方式是[email protected]。