貌似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#引用声明:
[System.Runtime.InteropServices.DllImport("dwmapi.dll")]public extern static int DwmIsCompositionEnabled(ref int en ) ; //该函数用于判断Aero合成效果是否打开,否则无法看到磨砂效果[System.Runtime.InteropServices.DllImport("dwmapi.dll")]public extern static int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margin ) ; //该函数用于扩展玻璃区域要注意DwmExtendFrameIntoClientArea函数最后一个参数为MARGINS 结构体,用于确定要扩展的玻璃区域距离窗体上下左右边框的距离大小,它的定义为:
public struct MARGINS...{ public int m_left; public int m_right; public int m_top; public int m_buttom};如果你要把整个窗口都变成玻璃,只需把MARGINS所有成员设为-1。下面是一段示例代码:
int en=0;MARGINS mg=new MARGINS();mg.m_Buttom = -1;mg.m_Left = -1;mg.m_Right = -1;mg.m_Top = -1 ;//确保你使用的是Vistaif (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之后不可用,就不做介绍了。
void Form1_Paint(object sender, PaintEventArgs e) ...{ //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填充到窗体上:
Graphics g = this.CreateGraphics();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在玻璃区域上画出像标题文字一样的带白色渐变效果的文本,我会在后面的文章里介绍,这里先给大家看看效果图: