分享

利用.net(C#)在Vista磨砂玻璃窗口上正确画出文字和图片(GDI 版)

 Cloud书屋 2012-11-21

本文欢迎转载,但请标明出处.

作者: 吴滂

 貌似Windows Vista昨天正式发布了,也是该写写东西的时候啦,其实这篇文章我很早就写了的,不过是用E文写的,发表在codeproject上:

http://www./vista/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 ;
//确保你使用的是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之后不可用,就不做介绍了。

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, 26new Point(00), StringFormat.GenericDefault);

//SmoothingMode 是必须的, 否则会看到文本的锯齿边缘

g.SmoothingMode 
= System.Drawing.Drawing2D.SmoothingMode.HighQuality  ;   
g.FillPath(brsh, blackfont);    
//用白色填充文本

效果:

当然,如果你只是画图片到玻璃区域,Graphics的DrawImage就足够了:

当然,这种画文本的方法并不是Windows的“标准方法”,至于如何利用API在玻璃区域上画出像标题文字一样的带白色渐变效果的文本,我会在后面的文章里介绍,这里先给大家看看效果图:

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多