代码改变世界

C#如何实现渐显窗口[原创]

2006-10-07 10:11  老博客哈  阅读(3364)  评论(2编辑  收藏  举报

也许大家曾经用过一些软件,具有渐显淡出的效果, 一个很好的例子就是千千静听。那么在C#当中我们应该如何实现此种特效呢,就让我娓娓道来吧。

我想给大家介绍一下Windows Form。Windows Form 是.Net当中经常看见的一个术语。
它是一个可以用来为用户提供信息以及接受其输入的窗口。我们通过Visual Studio.Net建一个Windows Application的时候,就生成了一个windows窗体。通常我们对Windows Form操作的相关类在System.Windows.Forms名字空间下面(这就是为什么默认情况下References里面有System.Windows.Forms的引用,顶部有对该名字空间对引用的原因拉, 用户建立空的解决方案时添加此类的项目时需要把二者都加入)。这个名字空间下面包含了大约200个类,大多数类在后台操作或者被可视化操作。要注意的是:千万不要认为.Net Framework可以完全取代Win32 API, 不可否认,它的确很庞大很丰富,但是对于一些特殊的操作,还是要去使用API的。

好了,扯的远了, 言归正传。那么谈到了Windows Form, 先谈谈Form类,这个类是Windows Form的基础,细心的您可能发现,每一个生成的Form都是继承于Form类(自己写的Form也可以)。关于这方面的OO的问题我就不说了,大家自己温习一下。嗯,怎么又扯远了。。。 这个Form类下面有一个Opacity属性。这个就是此篇文章的重点了。这个是调节窗体透明度的。顺便就把MSDN中的内容给摘过来了:
Form.Opacity 属性  [C#]
获取或设置窗体的不透明度级别。

[C#]
public double Opacity {get; set;}

属性值
窗体的不透明度级别。默认值为 1.00。

备注
此属性使您得以指定窗体及其控件的透明度级别。此属性与 TransparencyKey 提供的透明度不同,后者只能使窗体及其控件完全透明,条件是当窗体及其控件与 TransparencyKey 属性中指定的值所表示的颜色相同。当将此属性设置为小于 100% (1.00) 的值时,将使整个窗体(包括边框)更透明。将此属性设置为值 0% (0.00) 时,将使该窗体完全不可见。可以使用此属性提供不同级别的透明度,或者提供如窗体逐渐进入或退出视野这样的效果。例如,可以通过将 Opacity 属性设置为值 0% (0.00),并逐渐增加该值直到它到达 100% (1.00),来使某窗体逐渐进入视野。

Windows 2000, Windows Server 2003 系列平台说明:  此属性在无法显示分层窗口的平台上不起作用。

示例
[Visual Basic, C#] 下面的示例演示如何创建以 75%不透明度显示的窗体。该代码示例创建一个新窗体,该窗体位于屏幕的中央,其 Opacity 属性被设置为更改窗体的不透明度。该代码示例还设置 Size 属性来提供大于默认窗体大小的窗体。该示例假定在该示例中定义的方法是从事件处理程序的另一个窗体或其他方法中调用。

[C#]

private void CreateMyOpaqueForm()
{
   
// Create a new form.
   Form form2 = new Form();
   
// Set the text displayed in the caption.
   form2.Text = "My Form";
   
// Set the opacity to 75%.
   form2.Opacity = .75;
   
// Size the form to be 300 pixels in height and width.
   form2.Size = new Size(300,300);
   
// Display the form in the center of the screen.
   form2.StartPosition = FormStartPosition.CenterScreen;

   
// Display the form as a modal dialog box.
   form2.ShowDialog();
}


  要求
平台: Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003 系列

这个知道了, 大家应该有所启发了。
下面就从劣到优,逐渐改进我们的想法。
方法一:延时一段时间,逐渐改变窗体的Opacity值。
关于延时,我们可以使用空循环或者主线程Sleep实现(经试验,两者表现的结果类似)
我这里用后者来实现。
名字空间要加上 using System.Threading;
       

       private void Form1_Load(object sender, EventArgs e)
        {
            
this.Opacity = 0.0;
        }

        
private void Form1_Shown(object sender, EventArgs e)
        {
            
while (this.Opacity < 1.0)
            {
                Thread.Sleep(
100);
                
this.Opacity += 0.05;
            }
        }

在Load事件里面为Opacity赋值0.0,这样窗口初始时为完全透明,后面在窗口第一次显示的时候
进行Opacity的改变, 让主线程每次睡上100ms,透明度以0.05步进。(注意代码所放的函数, 不要放错了, 否则达不到渐显的效果),同样要达到淡出, 我们只要在Closing动作的时候加上透明度减小就可以了。

 
       private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            
while (this.Opacity > 0.0)
            {
                Thread.Sleep(
100);
                
this.Opacity -= 0.05;
            }
        }

注:这个淡出的时候会有点黑色。
上面的方法在窗口启动时, 光标会变成等待状, 很不雅观,因此有下面的方法了。
方法二: 有了上面的想法之后, 当然会想起来用时钟控件了啊。
说做就做。
把timer的Interval设置为100(默认就是100)
然后在FormLoad的时候把timer1的Enabled设置为true(初始时为false)
      
 
       private void timer1_Tick(object sender, EventArgs e)
        {
            
if (this.Opacity < 1.0)
            {
                
this.Opacity += 0.05;
            }
            
else
            {
                timer1.Enabled 
= false;
            }
      }
这样就不会有等待光标了。这个淡出比较麻烦, 我没有想到用timer的方法。

方法三: 调用API
AnimateWindow
同样的,为了给我省点口水。我摘MSDN:
AnimateWindow Function

--------------------------------------------------------------------------------

The AnimateWindow function enables you to produce special effects when showing or hiding windows. There are four types of animation: roll, slide, collapse or expand, and alpha-blended fade.

Syntax

BOOL AnimateWindow(          HWND hwnd,
    DWORD dwTime,
    DWORD dwFlags
);
Parameters

hwnd
[in] Handle to the window to animate. The calling thread must own this window.
dwTime
[in] Specifies how long it takes to play the animation, in milliseconds. Typically, an animation takes 200 milliseconds to play.
dwFlags
[in] Specifies the type of animation. This parameter can be one or more of the following values. Note that, by default, these flags take effect when showing a window. To take effect when hiding a window, use AW_HIDE and a logical OR operator with the appropriate flags.
AW_SLIDE
Uses slide animation. By default, roll animation is used. This flag is ignored when used with AW_CENTER.
AW_ACTIVATE
Activates the window. Do not use this value with AW_HIDE.
AW_BLEND
Uses a fade effect. This flag can be used only if hwnd is a top-level window.
AW_HIDE
Hides the window. By default, the window is shown.
AW_CENTER
Makes the window appear to collapse inward if AW_HIDE is used or expand outward if the AW_HIDE is not used. The various direction flags have no effect.
AW_HOR_POSITIVE
Animates the window from left to right. This flag can be used with roll or slide animation. It is ignored when used with AW_CENTER or AW_BLEND.
AW_HOR_NEGATIVE
Animates the window from right to left. This flag can be used with roll or slide animation. It is ignored when used with AW_CENTER or AW_BLEND.
AW_VER_POSITIVE
Animates the window from top to bottom. This flag can be used with roll or slide animation. It is ignored when used with AW_CENTER or AW_BLEND.
AW_VER_NEGATIVE
Animates the window from bottom to top. This flag can be used with roll or slide animation. It is ignored when used with AW_CENTER or AW_BLEND.
Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. The function will fail in the following situations:

If the window uses the window region. Windows XP: This does not cause the function to fail.
If the window is already visible and you are trying to show the window.
If the window is already hidden and you are trying to hide the window.
If there is no direction specified for the slide or roll animation.
When trying to animate a child window with AW_BLEND.
If the thread does not own the window. Note that, in this case, AnimateWindow fails but GetLastError returns ERROR_SUCCESS.
To get extended error information, call the GetLastError function.

 


Remarks

To show or hide a window without special effects, use ShowWindow.

When using slide or roll animation, you must specify the direction. It can be either AW_HOR_POSITIVE, AW_HOR_NEGATIVE, AW_VER_POSITIVE, or AW_VER_NEGATIVE.

You can combine AW_HOR_POSITIVE or AW_HOR_NEGATIVE with AW_VER_POSITIVE or AW_VER_NEGATIVE to animate a window diagonally.

The window procedures for the window and its child windows should handle any WM_PRINT or WM_PRINTCLIENT messages. Dialog boxes, controls, and common controls already handle WM_PRINTCLIENT. The default window procedure already handles WM_PRINT.

If a child window is displayed partially clipped, when it is animated it will have holes where it is clipped.

AnimateWindow supports RTL windows.

Avoid animating a window that has a drop shadow because it produces visually distracting, jerky animations.

Function Information

Header Declared in Winuser.h, include Windows.h
Import library User32.lib
Minimum operating systems Windows 98, Windows 2000


C#当中如何调用API, 我在以前的一篇《简单音频函数PlaySound》一文中已经用到过,这里就不多说了。
好了, 直接代码奉上。很容易理解了。

 
       public const Int32 AW_HOR_POSITIVE = 0x00000001;
        
public const Int32 AW_HOR_NEGATIVE = 0x00000002;
        
public const Int32 AW_VER_POSITIVE = 0x00000004;
        
public const Int32 AW_VER_NEGATIVE = 0x00000008;
        
public const Int32 AW_CENTER = 0x00000010;
        
public const Int32 AW_HIDE = 0x00010000;
        
public const Int32 AW_ACTIVATE = 0x00020000;
        
public const Int32 AW_SLIDE = 0x00040000;
        
public const Int32 AW_BLEND = 0x00080000;
        [DllImport(
"user32.dll", CharSet = CharSet.Auto)]
        
public static extern bool AnimateWindow(
            IntPtr hwnd, 
// handle to window 
            int dwTime, // duration of animation 
            int dwFlags // animation type 
            ); 
      
        
private void Form1_Load(object sender, EventArgs e)
        {
            AnimateWindow(
this.Handle, 2000, AW_CENTER | AW_ACTIVATE | AW_BLEND);
        }

        
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            AnimateWindow(
this.Handle, 2000, AW_HIDE | AW_BLEND);
        }


这里还是有等待光标, 估计内部实现还是用的延时操作。这个AnimateWindow很奇怪,放到Shown里面竟然没有用, 放到Load或者构造函数下面就可以了,真是奇怪。其他的特效大家自己试试, 挺炫的哦。

就到这为止吧,大家有问题就Email我吧。中间碰到的一点点问题如果有哪位高手知道的,还望不吝指教。