现在的位置: 首页 > 综合 > 正文

一种用户小体验 – 从那里来就回到那里去

2013年09月20日 ⁄ 综合 ⁄ 共 12647字 ⁄ 字号 评论关闭

 各位都用过Word2000吧,它的用户界面中有个小动画,你按下Ctl+F弹出查找对话框时,会从右下角显示一个黑色的方框,然后快速移动和放大,最后才显示出查找对话框,当用户关闭查找对话框时刚才的动画就会倒放。

这个用户界面的小体验不错,它清晰的表明了若使用鼠标点击操作时点击何处来打开查找对话框,帮助用户记忆操作过程,这个动画本身就是一个操作帮助和提醒。可以称之为从那里来就回到那里去的过程。

于是我编写了一个 AnimatedRectDrawer 类型来模仿了这种用户体验,这个类型实际上是Win32API函数 DrawAnimatedRects 用C#的一个包装。它可以将子窗体和主窗体上的某个按钮或其他控件绑定,当用户点击按钮时,子窗体将从这个按钮上动态的弹出来,用户关闭子窗体时,子窗体将动态的收缩到按钮中。过程很形象,而且用户比较牢固的记下按钮和子窗体的关系。

整个代码如下,在Win2000下调试成功。

 

//#define DOTNET20

using System;
using System.Text;

namespace XDesignerWindows32
{
 
    
//
    
//      !!!!!!!!! 注意 !!!!!!!!!!!!!!!!
    
//
    
//.NET1.1的窗体关闭事件 Form.Closed 在 .NET2.0中是过时的。在.NET2.0环境中
    
//
    
// 应当使用 Form.FormClosed 事件,这两个事件名称和使用的委托类型都不一样,为此
    
//
    
// 定义一个名为 DOTNET20 的条件编译标志,若编译环境使用.NET1.1则不需要定义这个
    
//
    
// 条件编译变量,若编译环境使用 .NET2.0则建议定义这个条件编译标记,即在代码文件
    
//
    
// 的第一行添加    #define DOTNET20
    
//
    
// 由于.NET2.0保持兼容性还支持Form.Closed事件,因此当不定义这个条件编译标记而
    
//
    
// 使用 Form.Closed 事件仍然可以编译通过,但仍建议进行上述的处理。
    
//
    
// 袁永福( http://www.xdesigner.cn ) 2006-12-12
    
//
    
//
    
//   !!!!!!!!!!!!!!! Notice !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
// 
    
// Form.Close event used in .NET1.1 is old in .NET2.0 . In .NET2.0 , It is 
    
//
    
// replace by Form.FormClosed , The two event 's name and delegate type is 
    
// 
    
// different , so there are define a pre-compile flag named DOTNET20 , when 
    
//
    
// you compile this code use .NET1.1 , you did not define this pre-compile 
    
//
    
// flag , but when you compile use .NET2.0 , I advice you define this pre-compile
    
//
    
// flag , just add "#define DOTNET20" at the begin of this code file .
    
//
    
// For compatibility , .NET2.0 support Form.Close , so if you did not define this
    
//
    
// pre-compile flag and use Form.Close event , you can compile success , but I 
    
//
    
// still advice you define the DOTNET20 flag needed .
    
//
    
// yfyuan ( http://www.xdesigner.cn/default-eng.htm ) 2006-12-12
    
//
 
    
/// <summary>
    
/// 绘制矩形动画的模块,本模块为Win32API函数 DrawAnimatedRects 的一个包装
    
/// 
    
/// Draw animate rectangle , this class is a package of Win32API 
    
/// 
    
/// function DrawAnimatedRects
    
/// 
    
/// </summary>
    
/// <remarks>
    
/// 编写 袁永福( http://www.xdesigner.cn ) 2006-12-12
    
/// 
    
/// Author yfyuan ( http://www.xdesigner.cn/default-eng.htm ) 2006-12-12
    
/// </remarks>
    public class AnimatedRectDrawer
    {
        
/// <summary>
        
/// 注册项目类型
        
/// 
        
/// Information of regite form
        
/// </summary>
        public class DrawInfoItem
        {
            
/// <summary>
            
/// 原始控件
            
/// 
            
/// Source Control
            
/// </summary>
            public System.Windows.Forms.Control SourceControl = null;
            
/// <summary>
            
/// 原始区域
            
/// 
            
/// Source Rectangle
            
/// </summary>
            public System.Drawing.Rectangle SourceRect = System.Drawing.Rectangle.Empty;
            
/// <summary>
            
/// 目标窗体
            
/// 
            
/// Desc Form object
            
/// </summary>
            public System.Windows.Forms.Form Form = null;
            
/// <summary>
            
/// 对象额外数据
            
/// 
            
/// object's extern data
            
/// </summary>
            public object Tag = null;
        }

        /// <summary>
        
/// 初始化对象
        
/// 
        
/// Init object
        
/// </summary>
        public AnimatedRectDrawer()
        {

#if DOTNET20
            _FormClosed 
= new System.Windows.Forms.FormClosedEventHandler(Form_Closed);
#else
            _FormClosed 
= new System.EventHandler(Form_Closed);
#endif
            _FormLoad 
= new EventHandler(Form_Load);
        }
        
/// <summary>
        
/// 添加项目
        
/// 
        
/// Add item
        
/// </summary>
        
/// <param name="ctl">原始控件 Source control</param>
        
/// <param name="rect">原始矩形 source rectangle</param>
        
/// <param name="frm">目标窗体 desc form</param>
        
/// <returns>新增的项目对象 the item instance added </returns>
        public DrawInfoItem Add(
            System.Windows.Forms.Control ctl,
            System.Drawing.Rectangle rect, 
            System.Windows.Forms.Form frm)
        {
            DrawInfoItem item 
= GetItem(frm);
            
if (item == null)
            {
                item 
= new DrawInfoItem();
                myItems.Add(item);
                frm.Load 
+= _FormLoad;
#if DOTNET20
                frm.FormClosed 
+= _FormClosed;
#else
                frm.Closed 
+= _FormClosed;
#endif
            }
            item.SourceControl 
= ctl;
            item.SourceRect 
= rect;
            item.Form 
= frm;
            
return item;
        }
        
/// <summary>
        
/// 添加项目 
        
/// 
        
/// Add item
        
/// </summary>
        
/// <param name="ctl">原始控件 source control</param>
        
/// <param name="frm">目标窗体 desc form</param>
        
/// <returns>新增的项目对象 the item instance added</returns>
        public DrawInfoItem Add(
            System.Windows.Forms.Control ctl,
            System.Windows.Forms.Form frm)
        {
            
return Add(ctl, System.Drawing.Rectangle.Empty, frm);
        }
        
/// <summary>
        
/// 删除所有项目
        
/// </summary>
        public void Clear()
        {
            myItems.Clear();
        }
        
/// <summary>
        
/// 为窗体查找项目对象
        
/// Search item for specify form instance
        
/// </summary>
        
/// <param name="frm">窗体对象 form instance</param>
        
/// <returns>
        
/// 找到的项目对象,若未找到则返回空引用
        
/// item instance finded , if can not find then return null 
        
/// </returns>
        public DrawInfoItem GetItem(System.Windows.Forms.Form frm)
        {
            
foreach (DrawInfoItem item in myItems)
            {
                
if (item.Form == frm)
                    
return item;
            }
            
return null;
        }

        #region 内部代码群 Internal code **************************************
        
/// <summary>
        
/// 注册项目列表
        
/// 
        
/// registe information list
        
/// </summary>
        private System.Collections.ArrayList myItems = new System.Collections.ArrayList();
        
/// <summary>
        
/// 窗体关闭处理程序委托对象
        
/// 
        
/// the delegate instance handle form close event 
        
/// </summary>
#if DOTNET20
        
private System.Windows.Forms.FormClosedEventHandler _FormClosed = null;
#else
        
private System.EventHandler _FormClosed = null;
#endif
        
/// <summary>
        
/// 窗体打开处理程序委托对象
        
/// 
        
/// the delegate instance handle form load event
        
/// </summary>
        private System.EventHandler _FormLoad = null;
        
/// <summary>
        
/// 窗体打开处理过程 the function handle form load event
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
        private void Form_Load(object sender, System.EventArgs e)
        {
            DrawInfoItem item 
= GetItem((System.Windows.Forms.Form)sender);
            
if (item != null)
            {
                InnerDraw(item, 
true);
            }

        }
        /// <summary>
        
/// 窗体关闭处理过程 the function handle form close event
        
/// </summary>
        
/// <param name="sender"></param>
        
/// <param name="e"></param>
#if DOTNET20
        
private void Form_Closed(
            
object sender, 
            System.Windows.Forms.FormClosedEventArgs e)
#else
        
private void Form_Closed( object sender , System.EventArgs e )
#endif
        {
            DrawInfoItem myItem 
= GetItem((System.Windows.Forms.Form)sender);
            
if (myItem != null)
            {
                myItems.Remove(myItem);
                InnerDraw(myItem, 
false);
            }
        }
        
/// <summary>
        
/// 内部的绘制动画的过程 interior function to draw animate rectangle
        
/// </summary>
        
/// <param name="item">绘制信息对象 registe information</param>
        
/// <param name="bolOpen">
        
/// 是否显示为打开过程 
        
/// draw animate as open form
        
/// </param>
        private void InnerDraw(DrawInfoItem item, bool bolOpen)
        {
            
if (item == null)
                
return;
            
            
if (item.SourceControl == null || item.Form == null)
                
return;

            System.Drawing.Rectangle srect = this.GetScreenRect(
                item.SourceRect, 
                item.SourceControl);

            if (srect.IsEmpty)
                
return;

            System.Drawing.Rectangle trect = this.GetScreenRect(
                System.Drawing.Rectangle.Empty,
                item.Form);

            if (trect.IsEmpty)
                
return;

            RECT rect1 = new RECT();
            rect1.left 
= srect.Left;
            rect1.top 
= srect.Top;
            rect1.right 
= srect.Right;
            rect1.bottom 
= srect.Bottom;

            RECT rect2 = new RECT();
            rect2.left 
= trect.Left;
            rect2.top 
= trect.Top;
            rect2.right 
= trect.Right;
            rect2.bottom 
= trect.Bottom;

            if (bolOpen)
                DrawAnimatedRects(item.Form.Handle, IDANI_CAPTION, 
ref rect1, ref rect2);
            
else
                DrawAnimatedRects(item.Form.Handle, IDANI_CAPTION, 
ref rect2, ref rect1);
        }

        private System.Drawing.Rectangle GetScreenRect(
            System.Drawing.Rectangle rect, 
            System.Windows.Forms.Control ctl)
        {
            System.Drawing.Rectangle result 
= System.Drawing.Rectangle.Empty;
            
if (ctl == null)
            {
                result 
= rect;
            }
            
else
            {
                result 
= GetControlBounds(ctl);
                
if (rect.IsEmpty)
                    result 
= GetControlBounds(ctl);
                
else
                {
                    result 
= rect;
                    result.Location 
= ctl.PointToScreen(result.Location);
                }
            }
            
return result;
        }
        
/// <summary>
        
/// 获得控件在屏幕中的矩形区域 get a control's bounds in screeen
        
/// </summary>
        
/// <param name="ctl">控件对象 control instance</param>
        
/// <returns>矩形区域对象 bounds in screen</returns>
        private System.Drawing.Rectangle GetControlBounds(System.Windows.Forms.Control ctl)
        {
            
if (ctl == null)
                
return System.Drawing.Rectangle.Empty;
            
if (ctl.IsHandleCreated)
            {
                RECT rect 
= new RECT();
                
if (GetWindowRect(ctl.Handle, ref rect))
                {
                    
return new System.Drawing.Rectangle(
                        rect.left, 
                        rect.top, 
                        rect.right 
- rect.left, 
                        rect.bottom 
- rect.top);
                }
            }
            
return ctl.Bounds;
        }

        #endregion

        #region 声明Win32API函数以及结构 declare Win32API function and structure

        private const int IDANI_CAPTION = 0x3;
        
private const int IDANI_CLOSE = 0x2;
        
private const int IDANI_OPEN = 0x1;

        private struct RECT
        {
            
public int left;
            
public int top;
            
public int right;
            
public int bottom;
        }

        [System.Runtime.InteropServices.DllImport("user32.dll")]
        
private static extern bool DrawAnimatedRects(
            IntPtr hwnd, 
            
int Ani, 
            
ref RECT from, 
            
ref RECT to);
        
        [System.Runtime.InteropServices.DllImport(
"user32.dll")]
        
private static extern bool GetWindowRect(IntPtr hwnd, ref RECT rect);

        #endregion
    }
//public class AnimatedRectDrawer

    /// <summary>
    
/// 测试 AnimatedRectDrawer 的功能的一个窗体
    
/// 
    
/// A form which test AnimatedRectDrawer's function
    
/// </summary>
    public class AnimatedRectDrawerTestForm : System.Windows.Forms.Form
    {
        
public AnimatedRectDrawerTestForm()
        {
            
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            
this.Text = "从那里来就回到那里去 - Where come from , where come back";
            
            btn 
= new System.Windows.Forms.Button();
            
this.Controls.Add(btn);
            btn.Text 
= "Open";
            btn.Location 
= new System.Drawing.Point(3030);
            btn.Click 
+= new EventHandler(btn_Click);
        }

        private AnimatedRectDrawer drawer = new AnimatedRectDrawer();
        System.Windows.Forms.Button btn 
= null;

        void btn_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.Form frm 
= new System.Windows.Forms.Form();
            drawer.Add(btn, frm);
            frm.Owner 
= this;
            frm.Show();
        }

        /// <summary>
        
/// Entrance function
        
/// </summary>
        [STAThread]
        
static void Main()
        {
            System.Windows.Forms.Application.Run(
new AnimatedRectDrawerTestForm());
        }
    }
//public class AnimatedRectDrawerTestForm : System.Windows.Forms.Form
}

 

 

袁永福 ( http://www.xdesigner.cn ) 2007

抱歉!评论已关闭.