貌似windows vista昨天正式发布了,也是该写写东西的时候啦,其实这篇文章我很早就写了的,不过是用e文写的,发表在codeproject上:
http://www.codeproject.com/useritems/textonglass.asp
当时用的是windows vista beta2 做的测试,演示有些地方已经和现在正式版(或者rc1)的系统不一样,不过功能还是照样能实现的。
现在我们就直入正题吧。windows vista给我们带来了磨砂玻璃的半透明窗体边框,其实这个效果是可以扩展到整个窗口区域的,让整个窗体成为一个“玻璃片”,效果就像在vista下按alt+tab键后看到的切换窗口一样。要达到这个效果,我们得借助于vista提供的一组新api :dwm(desktop windows manager) api。主要用到以下几个函数:dwmiscompositionenabled 和 dwmextendframeintoclientarea.
当然,调用api的话,p/invoke代码不可避免,这是这两个api的c#引用声明:
public extern static int dwmiscompositionenabled(ref int en ) ; //该函数用于判断aero合成效果是否打开,否则无法看到磨砂效果
public extern static int dwmextendframeintoclientarea(intptr hwnd, ref margins margin ) ; //该函数用于扩展玻璃区域
要注意dwmextendframeintoclientarea函数最后一个参数为margins 结构体,用于确定要扩展的玻璃区域距离窗体上下左右边框的距离大小,它的定义为:
{
public int m_left;
public int m_right;
public int m_top;
public int m_buttom
};
如果你要把整个窗口都变成玻璃,只需把margins所有成员设为-1。下面是一段示例代码:
margins mg=new margins();
mg.m_buttom = –1;
mg.m_left = –1;
mg.m_right = –1;
mg.m_top = –1 ;
//确保你使用的是vista
if (system.environment.osversion.version.major >= 6)
{
dwmiscompositionenabled(ref en); //检测aero合成已经被打开
if(en>0)
{
dwmextendframeintoclientarea(this.handle, ref mg);
}else{
messagebox.show(“desktop composition is disabled!“);
}
}else{
messagebox.show(“please run this on windows vista.“);
}
如果你这时按下f5,会发现看不到任何特殊的效果:窗体还是和原来一样。那是因为系统在本来应该是玻璃的区域自动用默认背景色填充了,以致于看不到效果。这个时候,我们必须在paint事件上做写些脚,把整个窗体用纯黑填充(rgb(0,0,0)刚好和argb的100%透明有着一样的bit pattern ),本来还有一个办法能看到效果,就是设置透明颜色让背景透明,但是这个方法已经在rc1的vista之后不可用,就不做介绍了。
{
//throw new exception(“the method or operation is not implemented.”);
solidbrush bsh;
bsh = new solidbrush(color.fromargb(convert.toint32(bgalpha.text ),color.black ));
graphics g = e.graphics;
g.fillrectangle(bsh, this.picturebox2.clientrectangle ); //picturebox2铺满整个窗体
bsh.dispose();
}
这样就可以看到效果:
实现了玻璃效果后你很快会发现问题:图片框和label不能正确的显示文字,文本框文字的黑色部分也会变成玻璃效果:
用graphics的drawstring也无法在玻璃上面画出正常的文本。为了能正确的画出文本,我们不能直接使用graphic对象,而必须先把要画的字“写”在一个path对象上面,最后再把path用graphics.fillpath填充到窗体上:
graphicspath blackfont = new graphicspath();
solidbrush brsh = new solidbrush(color.white);
blackfont.addstring(“hello vista“, new fontfamily(“tahoma“,
(int)fontstyle.regular, 26, new point(0, 0), stringformat.genericdefault);
//smoothingmode 是必须的, 否则会看到文本的锯齿边缘
g.smoothingmode = system.drawing.drawing2d.smoothingmode.highquality ;
g.fillpath(brsh, blackfont); //用白色填充文本
效果:
当然,如果你只是画图片到玻璃区域,graphics的drawimage就足够了:
当然,这种画文本的方法并不是windows的“标准方法”,至于如何利用api在玻璃区域上画出像标题文字一样的带白色渐变效果的文本,我会在后面的文章里介绍,这里先给大家看看效果图: