这可能是个老题长谈的问题了,只是在项目中会用到这个效果,所以今天做个记录。大家见了别喷我。在项目中的需求是这样的。

打开程序,在屏幕的右下角会显示一个窗体,一般情况下该窗体会隐藏停靠在右边,只露出很小部分,当鼠标移动到这个很小部分时,窗体全部显示,显示过程是从右边滑动到左边,当鼠标离开窗体时,窗体需要隐藏在右边,只露出很小部分,隐藏过程是从左边滑动到右边。

实现此类效果我碰到的连个难点是:1、如何判断鼠标离开了窗体?2、窗体显示隐藏过程中效果如何表现平滑(就是给人一种流畅感觉)?

1、判断鼠标离开窗体我开始想的是在WndProc方法中来获取鼠标坐标然后根据窗体的Location来判断,可能是小弟愚笨,该方法没有处理好,运行后界面卡住了。然后我只有用个计时器,每隔几秒获取一下鼠标坐标在根据窗体的Location来判断。获取坐标有个API方法GetCursorPos,有资料表明此方法是最优效率的,那我们就用它好了。

2、显示隐藏效果开始想的也是改变窗体坐标来实现,但是这个方法做出来的效果比较差,画面感觉不流畅,后来查到可以用API方法AnimateWindow来实现这个效果,因此我们来认识一下AnimateWindow()方法;

此方法需要传递三个参数:

第一个参数:传入需要显示特效的窗体的句柄。

第二个参数:完成特效所花时间,单位:毫秒,也就是说你可以指定多少时间内完成指定的特效

第三个参数:指定特效类型,此参数可以指定多个,多个之间用|隔开。这里列举了一般的9个特效。有这9个基本够用了。

关于这个方法的详细资料我就不一一列举了,大家在网上搜搜,很多资料的。下面进入正题。

1、建一个winform项目,命名:DockFormsApplication,名字大家可以自定义的。

2、建完后项目中会有个默认创建好的窗体Form1,修改Form1的text属性为:“仿QQ停靠,加特效”

3、添加API方法AnimateWindow()和该方法需要的一些特效参数, 特效参数命名是我自己随便命名的,大家就不要深究了,至于为什么要这么命名,我自己也不知道,反正能用就行

注意:AnimateWindow()方法需要引用using System.Runtime.InteropServices;

        /// <summary>/// //从左到右/// </summary>public const Int32 AW_HOR_LEFT_RIGHT = 0x00000001;/// <summary>/// 从右到左/// </summary>private const Int32 AW_HOR_RIGHT_LEFT = 0x00000002;/// <summary>/// 从上到下/// </summary>private const Int32 AW_VER_UP_DOWN = 0x00000004;/// <summary>/// 从下到上/// </summary>private const Int32 AW_VER_DOWN_UP = 0x00000008;/// <summary>/// 从中间到四周/// </summary>private const Int32 AW_CENTER = 0x00000010;/// <summary>/// 隐藏窗口/// </summary>private const Int32 AW_HIDE = 0x00010000;/// <summary>/// 显示窗口/// </summary>private const Int32 AW_ACTIVATE = 0x00020000;/// <summary>/// 使用滑动类型。缺省则为滚动动画类型。当使用AW_CENTER标志时,这个标志就被忽略/// </summary>private const Int32 AW_SLIDE = 0x00040000;/// <summary>/// 改变透明度/// </summary>private const Int32 AW_BLEND = 0x00080000;/// <summary>/// 特效花费时间 单位:毫秒/// </summary>private int _speed = 500;[DllImport("user32.dll")]public static extern void AnimateWindow(IntPtr hwnd, int stime, int style);//显示效果

3、添加API方法GetCursorPos用于获取鼠标坐标。此方法需要传入一个坐标对象。该对象是一个二维结构。存储坐标的X值和Y值。

        /// <summary>/// 鼠标坐标/// </summary>private Point _cursorPoint;//API获取鼠标坐标[DllImport("user32.dll")]public static extern bool GetCursorPos(out Point pt);

4、设置窗体显示在右下角,并且重写WndProc方法禁止鼠标拖动和双击标题栏最大化

        private void Form1_Load(object sender, EventArgs e){//设置窗体显示位置 右下角int workY = Screen.PrimaryScreen.WorkingArea.Height - Height;int X = Screen.PrimaryScreen.Bounds.Width - Width;this.Location = new Point(X, workY);}//重写WndProc方法,禁止拖动和双击标题栏最大化protected override void WndProc(ref Message m){if (m.Msg == 0x231){this.SuspendLayout();}else if (m.Msg == 0x232){this.ResumeLayout();}else if (m.Msg == 0xA1 && m.WParam.ToInt32() == 2)//禁止拖动
            {return;}base.WndProc(ref m);}

后来发现,更改窗体属性:FormBorderStyle值为:FixedSingle也可以达到禁止拖动的效果

5、因为要每隔几秒获取鼠标坐标判断鼠标是否在窗体范围内,因此需要一个计时器。考虑到性能神马的,我比较喜欢使用System.Threading.Timer,下面就是计时器嗦必须的几个变量

注意:这里我需要说明一下,由于AnimateWindow()方法控制窗体特效只能窗体显示和隐藏两种状态,每个特效完成后窗体要么隐藏,要么显示,如何使特效过后窗体一直显示,我想了个折中办法,只要你隐藏了,我就再把你显示出来,因此在计时器中需要对窗体进行操作,如此则需要跨线程访问窗体,因此就需要使用委托了,然后Invoke就可以了。

        //线程暂停时间 单位:毫秒private int _timespan = 1000;private System.Threading.Timer _timer;private delegate void LoadListDelegate();private LoadListDelegate _loaddelegate;

6、程序逻辑需要的几个变量

        /// <summary>/// 窗体是否显示,true——显示、false——隐藏/// </summary>private bool _isActive = true;/// <summary>/// 停靠在边缘时,显示窗体的宽度/// </summary>private const int _smallX = 5;

7、添加两个方法,显示窗体和隐藏窗体的两个方法

        /// <summary>/// 隐藏窗体/// </summary>private void SetHide(){if (_isActive){AnimateWindow(this.Handle, _speed, AW_HOR_LEFT_RIGHT | AW_SLIDE | AW_HIDE);int X = Screen.PrimaryScreen.Bounds.Width - _smallX;int Y = this.Location.Y;this.Location = new Point(X, Y);AnimateWindow(this.Handle, 10, AW_BLEND | AW_ACTIVATE);_isActive = false;}}/// <summary>/// 显示窗体/// </summary>private void SetActivate(){if (!_isActive){AnimateWindow(this.Handle, 10, AW_BLEND | AW_HIDE);int X = Screen.PrimaryScreen.Bounds.Width - Width;int Y = this.Location.Y;this.Location = new Point(X, Y);AnimateWindow(this.Handle, _speed, AW_HOR_RIGHT_LEFT | AW_SLIDE | AW_ACTIVATE);_isActive = true;}}

8、添加方法,判断鼠标是否在窗体范围内,如果在范围内,则显示窗体,如果不在范围内,则停靠在右边并隐藏窗体

        private void LoadControl(){#region 控制窗体显示和隐藏//获取当前鼠标坐标GetCursorPos(out _cursorPoint);//根据 窗体当前状态,判断窗体接下来是显示还是隐藏。if (_isActive){//当前窗体为显示,则接下来是隐藏//如果鼠标坐标不在窗体范围内,则设置窗体隐藏,否则不处理if (_cursorPoint.X < this.Location.X || _cursorPoint.Y < this.Location.Y){SetHide();}}else{//当前窗体为隐藏,则接下来是显示//如果鼠标坐标在窗体范围内,则设置窗体显示,否则不处理if (_cursorPoint.X >= this.Location.X && _cursorPoint.Y >= this.Location.Y){SetActivate();}}#endregion}

9、添加计时器,每隔1秒判断当前鼠标位置,因为用到委托,因此需要在构造方法中添加一行代码_loaddelegate = LoadControl;用于指定委托的方法:

        private void Form1_Load(object sender, EventArgs e){//设置窗体显示位置 右下角int workY = Screen.PrimaryScreen.WorkingArea.Height - Height;int X = Screen.PrimaryScreen.Bounds.Width - Width;this.Location = new Point(X, workY);//窗体打开的时候就开始计时器
            BeginTimer();}private void BeginTimer(){TimerCallback tcBack = new TimerCallback(InvokTimer);_timer = new System.Threading.Timer(tcBack, null, 5000, _timespan);}private void InvokTimer(object state){if (this.InvokeRequired){this.Invoke(_loaddelegate);}}

10、为了窗体一打开和关闭时有特效显示,需要重写OnLoad方法和实现Form1_Closing方法

        protected override void OnLoad(EventArgs e){base.OnLoad(e);//从右到左滑动AnimateWindow(this.Handle, _speed, AW_HOR_RIGHT_LEFT | AW_SLIDE | AW_ACTIVATE);}private void Form1_FormClosing(object sender, FormClosingEventArgs e){//淡出效果AnimateWindow(this.Handle, 1000, AW_BLEND | AW_HIDE);}

到此,所有代码编写完成,如果想要有更好的体验,可以设置一下窗体的以下属性值:

            this.MaximizeBox = false;//取消最大化按钮this.MinimizeBox = false;//取消最小化按钮this.ShowInTaskbar = false;//任务栏不显示窗体图标this.TopMost = false;//设置窗体总是显示在最前面

完整代码如下:

全部代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;namespace DockFormsApplication
{public partial class Form1 : Form{#region 属性 API特效窗体显示和隐藏/// <summary>/// //从左到右/// </summary>public const Int32 AW_HOR_LEFT_RIGHT = 0x00000001;/// <summary>/// 从右到左/// </summary>private const Int32 AW_HOR_RIGHT_LEFT = 0x00000002;/// <summary>/// 从上到下/// </summary>private const Int32 AW_VER_UP_DOWN = 0x00000004;/// <summary>/// 从下到上/// </summary>private const Int32 AW_VER_DOWN_UP = 0x00000008;/// <summary>/// 从中间到四周/// </summary>private const Int32 AW_CENTER = 0x00000010;/// <summary>/// 隐藏窗口/// </summary>private const Int32 AW_HIDE = 0x00010000;/// <summary>/// 显示窗口/// </summary>private const Int32 AW_ACTIVATE = 0x00020000;/// <summary>/// 使用滑动类型。缺省则为滚动动画类型。当使用AW_CENTER标志时,这个标志就被忽略/// </summary>private const Int32 AW_SLIDE = 0x00040000;/// <summary>/// 改变透明度/// </summary>private const Int32 AW_BLEND = 0x00080000;/// <summary>/// 特效花费时间 单位:毫秒/// </summary>private int _speed = 500;[DllImport("user32.dll")]public static extern void AnimateWindow(IntPtr hwnd, int stime, int style);//显示效果/// <summary>/// 鼠标坐标/// </summary>private Point _cursorPoint;//API获取鼠标坐标[DllImport("user32.dll")]public static extern bool GetCursorPos(out Point pt);//线程暂停时间 单位:毫秒private int _timespan = 1000;private System.Threading.Timer _timer;private delegate void LoadListDelegate();private LoadListDelegate _loaddelegate;/// <summary>/// 窗体是否显示,true——显示、false——隐藏/// </summary>private bool _isActive = true;/// <summary>/// 停靠在边缘时,显示窗体的宽度/// </summary>private const int _smallX = 5;#endregionpublic Form1(){InitializeComponent();this.MaximizeBox = false;//取消最大化按钮this.MinimizeBox = false;//取消最小化按钮this.ShowInTaskbar = false;//任务栏不显示窗体图标this.TopMost = false;//设置窗体总是显示在最前面
_loaddelegate = LoadControl;}private void Form1_Load(object sender, EventArgs e){//设置窗体显示位置 右下角int workY = Screen.PrimaryScreen.WorkingArea.Height - Height;int X = Screen.PrimaryScreen.Bounds.Width - Width;this.Location = new Point(X, workY);//窗体打开的时候就开始计时器
            BeginTimer();}protected override void OnLoad(EventArgs e){base.OnLoad(e);//从右到左滑动AnimateWindow(this.Handle, _speed, AW_HOR_RIGHT_LEFT | AW_SLIDE | AW_ACTIVATE);}private void Form1_FormClosing(object sender, FormClosingEventArgs e){_timer.Dispose();//淡出效果AnimateWindow(this.Handle, 1000, AW_BLEND | AW_HIDE);}//重写WndProc方法,禁止拖动和双击标题栏最大化protected override void WndProc(ref Message m){if (m.Msg == 0x231){this.SuspendLayout();}else if (m.Msg == 0x232){this.ResumeLayout();}else if (m.Msg == 0xA1 && m.WParam.ToInt32() == 2)//禁止拖动
            {return;}base.WndProc(ref m);}/// <summary>/// 隐藏窗体/// </summary>private void SetHide(){if (_isActive){AnimateWindow(this.Handle, _speed, AW_HOR_LEFT_RIGHT | AW_SLIDE | AW_HIDE);int X = Screen.PrimaryScreen.Bounds.Width - _smallX;int Y = this.Location.Y;this.Location = new Point(X, Y);AnimateWindow(this.Handle, 10, AW_BLEND | AW_ACTIVATE);_isActive = false;}}/// <summary>/// 显示窗体/// </summary>private void SetActivate(){if (!_isActive){AnimateWindow(this.Handle, 10, AW_BLEND | AW_HIDE);int X = Screen.PrimaryScreen.Bounds.Width - Width;int Y = this.Location.Y;this.Location = new Point(X, Y);AnimateWindow(this.Handle, _speed, AW_HOR_RIGHT_LEFT | AW_SLIDE | AW_ACTIVATE);_isActive = true;}}private void LoadControl(){#region 控制窗体显示和隐藏//获取当前鼠标坐标GetCursorPos(out _cursorPoint);//根据 窗体当前状态,判断窗体接下来是显示还是隐藏。if (_isActive){//当前窗体为显示,则接下来是隐藏//如果鼠标坐标不在窗体范围内,则设置窗体隐藏,否则不处理if (_cursorPoint.X < this.Location.X || _cursorPoint.Y < this.Location.Y){SetHide();}}else{//当前窗体为隐藏,则接下来是显示//如果鼠标坐标在窗体范围内,则设置窗体显示,否则不处理if (_cursorPoint.X >= this.Location.X && _cursorPoint.Y >= this.Location.Y){SetActivate();}}#endregion}private void BeginTimer(){TimerCallback tcBack = new TimerCallback(InvokTimer);_timer = new System.Threading.Timer(tcBack, null, 5000, _timespan);}private void InvokTimer(object state){if (this.InvokeRequired){this.Invoke(_loaddelegate);}}}
}

转载于:https://www.cnblogs.com/springSky/archive/2013/02/04/2891345.html

WinForm实现类似QQ停靠,显示隐藏过程添加特效效果相关推荐

  1. android RecyclerView一步步打造分组效果、类似QQ分组、折叠菜单、分组效果(二)

    第一篇链接: android RecyclerView一步步打造分组效果.类似QQ分组.折叠菜单.分组效果(一) 注!已更新代码! 上一篇写了分组效果的初步实现: 这一篇就继续增加分组折叠效果和基类的 ...

  2. android RecyclerView一步步打造分组效果、类似QQ分组、折叠菜单、分组效果(一)

    第二篇文章链接: android RecyclerView一步步打造分组效果.类似QQ分组.折叠菜单.分组效果(二) 效果图: 前言 之前看到这种效果如果用recyclerview来实现没有一点思路, ...

  3. php隐藏指定id的div,CSS_纯css3显示隐藏一个div特效的具体实现,复制代码代码如下: !DOCTYPE H - phpStudy...

    纯css3显示隐藏一个div特效的具体实现 复制代码代码如下: #showDiv { background-color:red; width:300px; height:300px; display: ...

  4. html 特效隐藏div,如何实现用css3显示隐藏一个div特效

    这篇文章主要介绍了关于如何实现用css3显示隐藏一个div特效,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 显示隐藏一个p特效的方法有很多,下为大家介绍下使用纯css3是如何实现的, ...

  5. 类似QQ管家会员页面的jquery轮换效果

    详细请点击:http://www.verydemo.com/demo_c98_i2455.html 喜欢看的好的效果收的习惯,最近jquery博客忙着整discuz等php程序,小站有点落下. 类似Q ...

  6. element-table在实现columns(表格列)显示隐藏过程中由于show-overflow-tooltip导致的渲染问题

    背景 刚开始为了写表格方便所以在使用element时候使用v-for循环来写,所以代码类似于如下 <el-table-columnv-for="(item, index) in tab ...

  7. .NET Winform也能画出类似QQ、飞信这样的窗口风格和控件效果

    MPN企业宝智能升级程序界面采用.NET的Winform技术,并没有延续企业宝主程序的绘制界面技术--WPF.直接采用Winform实现类似QQ和飞信的窗口风格比较困难,WPF好在还有一个Blend设 ...

  8. C# 实现类似QQ的窗体在桌面边缘停靠和隐藏

    设计思路: 1.使用定时器(Timer)来监控鼠标位置和窗体位置,并实现窗体的停靠和隐藏 2.当鼠标拖动窗体时,窗体才有可能根据自身位置决定是否停靠 3.如果窗体四周没有接触到屏幕边缘则不会停靠 4. ...

  9. Qt实现窗体在显示屏旁边自动隐藏(类似QQ)

    Qt实现窗体在显示屏旁边自动隐藏(类似QQ) 看群里有人问这个东西,本人闲来无事便依照自己的想法实现了下: 其实实现的点子很简单: void AutoHideWidget::leaveEvent(QE ...

最新文章

  1. Nodejs学习笔记之复制文件
  2. python 下载图片的集中方法
  3. 树莓派4直接运行linux,树莓派4最小化安装Linux
  4. ofstream写文件
  5. Builder 模式
  6. XStream – XStreamely使用Java中的XML数据的简便方法
  7. Redis配置和常用命令
  8. servlet/filter/listener/interceptor区别与联系(转)
  9. 不同种类的ICP算法
  10. 70进货卖100利润是多少_进货价8块的产品,在网上卖100块,这个电商卖家能赚多少!...
  11. mysql 定时器_MySQL定时器开启、调用实现代码
  12. JSP项目引入Vue.js进行项目开发(工程搭建)
  13. 深度装机大师一键重装_做好电脑重装系统前后的这些注意事项,让你从此摆脱装机忧愁!...
  14. Bootstrap系列---按钮
  15. Java环境变量配置与adb环境变量配置
  16. 3文聚焦:RNA m6A甲基化修饰在不同农作物中的研究进展(马铃薯+水稻+玉米+小麦)|易基因
  17. FreeRTOS个人笔记-初谈CM3内核
  18. PGN: 指针生成网络(Get To The Point: Summarization with Pointer-Generator Networks)
  19. 防火墙用户管理和入侵防御简介
  20. Python基础语法七:元组字典和集合

热门文章

  1. linux 4.0内核编译选项,linux 2.40.20-8 内核编译选项.doc
  2. mysql隔离级别 举例_mysql的事务隔离级别举例
  3. oracle notes,Oracle Notes
  4. freemarker生成word模板
  5. Linux LED驱动源码简析
  6. 51nod 1717 好数 (水题)
  7. 一个整数数组,每个数字都出现K次,只有一个数字出现M次,找出这个数字(线性时间)
  8. 1025 反转链表 (25 分)(c语言)
  9. 最大子序和—leetcode53
  10. C++操作符的优先级 及其记忆方法