您的位置:首页 > 其它

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

2006-12-12 16:20 162 查看
各位都用过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(30, 30);
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 ) 2006-12-12
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: