QQ有个靠边隐藏的功能,使用起来很方便:在屏幕上拖动QQ的主窗体,当窗体的上边沿与屏幕的上边沿对齐时,主窗体就会duang~~地隐藏起来,当将鼠标移到屏幕上边沿的对应区域时,主窗体又会duang~~显示出来。

  我在GG的最新版4.2中也增加了靠边隐藏的功能,支持靠左边沿隐藏、靠上边沿隐藏、靠右边沿隐藏三种模式,并且,将靠边隐藏实现为了一个可复用的组件AutoDocker。

那么,靠边隐藏功能到底是怎么实现的了?(最初实现的过程中,遇到了很多问题,花了不少时间,现在直接把成果共享出来)

想要直接下载体验的朋友请点击:“下载中心”

一.靠边隐藏的原理

靠边隐藏的本质实际上并不是将窗体的Visiable设为false,而是将整个窗体的位置挪到屏幕区域之外。比如,靠右边沿隐藏,实际的效果图如下所示:

方案说明如下:

(1)当拖动窗体在屏幕上移动时,检测窗体的位置,是否抵达了屏幕的边界,如果达到了边界,则准备靠边隐藏。

(2)当达到了隐藏条件,并且鼠标的光标已经离开了主窗体,则实现隐藏。

(3)窗体隐藏后,当鼠标的光标移动到窗体与屏幕相交的边界位置时,则正常显示窗体;之后:

a. 当鼠标再度离开窗体区域,则又隐藏窗体。

b.如果鼠标拖动窗体改变了其位置,使其不再满足隐藏的条件,则之后一直正常显示窗体。

二.具体实现过程

1.基本元素定义

  首先,我们需要定义靠边隐藏的类型:靠左、靠上、靠右。使用DockHideType枚举表示:

    /// <summary>/// 靠边隐藏的类型。/// </summary>public enum DockHideType{/// <summary>/// 不隐藏/// </summary>None = 0,/// <summary>/// 靠上边沿隐藏/// </summary>
        Top,/// <summary>/// 靠左边沿隐藏/// </summary>
        Left,/// <summary>/// 靠右边沿隐藏/// </summary>
        Right}

其次,根据上面的原理描述,我们知道窗体有三种状态:正常显示、准备隐藏、已经隐藏。这三种状态使用FormDockHideStatus枚举表示:

    /// <summary>/// 窗体的显示或隐藏状态/// </summary>public enum FormDockHideStatus{/// <summary>/// 已隐藏/// </summary>Hide = 0,/// <summary>/// 准备隐藏/// </summary>
        ReadyToHide,/// <summary>/// 正常显示/// </summary>
        ShowNormally}

2.判断是否达到隐藏条件

  很明显,我们应当在每次窗体的位置发生变化时,做出这样的判断,所以,这个判断应该在Form的LocationChanged事件中调用。

        private void dockedForm_LocationChanged(object sender, EventArgs e){this.ComputeDockHideType();if (!this.IsOrg){this.lastBoard = this.dockedForm.Bounds;this.IsOrg = true;}}/// <summary>/// 判断是否达到了隐藏的条件?以及是哪种类型的隐藏。/// </summary>private void ComputeDockHideType(){if (this.dockedForm.Top <= 0){this.dockHideType = DockHideType.Top;if (this.dockedForm.Bounds.Contains(Cursor.Position)){this.formDockHideStatus = FormDockHideStatus.ReadyToHide;return;}this.formDockHideStatus = FormDockHideStatus.Hide;return;}else{if (this.dockedForm.Left <= 0){this.dockHideType = DockHideType.Left;if (this.dockedForm.Bounds.Contains(Cursor.Position)){this.formDockHideStatus = FormDockHideStatus.ReadyToHide;return;}this.formDockHideStatus = FormDockHideStaus.Hide;return;}else{if (this.dockedForm.Left < Screen.PrimaryScreen.Bounds.Width - this.dockedForm.Width){this.dockHideType = DockHideType.None;this.formDockHideStatus = FormDockHideStatus.ShowNormally;return;}this.dockHideType = DockHideType.Right;if (this.dockedForm.Bounds.Contains(Cursor.Position)){this.formDockHideStatus = FormDockHideStatus.ReadyToHide;return;}this.formDockHideStatus = FormDockHideStatus.Hide;return;}}}

  上面的代码主要体现了以下几个要点:

(1)靠边的优先级判断:最先判断靠上边沿隐藏、其次判断靠左边沿隐藏、最后判断靠右边沿隐藏。

(2)只要窗体的某一边超出的屏幕的边界(比边沿对齐更加容易控制),则视为达到隐藏条件。

(3)如果达到了隐藏条件,仍然要判断光标的位置(Cursor.Position)是否在窗体内,如果在其内,则为准备隐藏状态。

详细分析一下上面的过程,就会发现,当处于准备隐藏状态时,如果将鼠标移出到窗体外(这次移动并没有拖动窗体改变其位置),那么,窗体会一直处于“准备隐藏”的状态。所以,此时,必须要有一个机制来触发它,真正进行隐藏动作。我是用一个定时器来循环判断的。

3.定时检测满足/退出隐藏条件

我使用一个定时器,每隔300ms检测一次,用于判断从正常显示到隐藏、以及从隐藏到正常显示的转变。

        /// <summary>/// 定时器循环判断。        /// </summary>       private void CheckPosTimer_Tick(object sender, EventArgs e){//当鼠标移动到窗体的范围内(此时,窗体的位置位于屏幕之外)if (this.dockedForm.Bounds.Contains(Cursor.Position)){                             if (this.dockHideType!= DockHideType.Top){if (this.dockHideType!= DockHideType.Left){if (this.dockHideType!= DockHideType.Right){return;}if (this.formDockHideStatus == FormDockHideStatus.Hide){this.dockedForm.Location = new Point(Screen.PrimaryScreen.Bounds.Width - this.dockedForm.Width, this.dockedForm.Location.Y);return;}}else{if (this.formDockHideStatus == FormDockHideStatus.Hide){this.dockedForm.Location = new Point(0, this.dockedForm.Location.Y);return;}}}else{if (this.formDockHideStatus == FormDockHideStatus.Hide){this.dockedForm.Location = new Point(this.dockedForm.Location.X, 0);return;}}}else //当鼠标位于窗体范围之外,则根据DockHideType的值,决定窗体的位置。
            {                switch (this.dockHideType){case DockHideType.None:{if (this.IsOrg && this.formDockHideStatus == FormDockHideStatus.ShowNormally &&                                (this.dockedForm.Bounds.Width != this.lastBoard.Width || this.dockedForm.Bounds.Height != this.lastBoard.Height)){this.dockedForm.Size = new Size(this.lastBoard.Width, this.lastBoard.Height);}break;}case DockHideType.Top:{this.dockedForm.Location = new Point(this.dockedForm.Location.X, (this.dockedForm.Height - 4) * -1);return;}      case DockHideType.Left:{                           this.dockedForm.Location = new Point(-1 * (this.dockedForm.Width - 4), this.dockedForm.Location.Y);return;}default:{if (anchorStyles2 != DockHideType.Right){return;}                            this.dockedForm.Location = new Point(Screen.PrimaryScreen.Bounds.Width - 4, this.dockedForm.Location.Y);return;}}}}

(1)在窗体隐藏的情况下,准确地说,是窗体在屏幕区域之外时,将鼠标光标移动到窗体上(实际上,是窗体的边界),则修改窗体的Location,让其正常显示。

(2)从(1)描述的窗体隐藏切换到正常显示时,代码对窗体的位置进行了控制,使其的边界恰好与屏幕的边界对齐,这样做的目的是,当鼠标再离开窗体范围时,窗体又可以duang隐藏起来。

(3)定时器的循环检测配合鼠标拖动窗体的事件处理,就完全实现了类似QQ的靠边隐藏的效果,而且,我们比QQ更强,QQ只实现了靠上隐藏。

三.如何使用AutoDocker组件

  AutoDocker是以组件(Component)的形式实现的,编译后,会在工具箱中出现一个AutoDocker组件。其使用非常简单:

从工具箱中将AutoDocker拖放到主窗体MainForm上,然后在主窗体的构造函数中添加一行代码:

  this.autoDocker1.Initialize(this);

  这样,主窗体运行起来后,就拥有了自动靠边隐藏的功能了,是不是很duang~~~

在GG 4.2的源码中,找到客户端项目(GG2014)下的AutoDocker.cs文件,即可详细研究靠边隐藏的实现细节。

四.GG V4.2 源码

  下载最新版本,请转到这里。

________________________________________________________________________

欢迎和我探讨关于 GG 和 GGMeeting 的一切,我的QQ:2027224508,多多交流!

大家有什么问题和建议,可以留言,也可以发送email到我邮箱:2027224508@qq.com。

如果你觉得还不错,请粉我,顺便再顶一下啊

转载于:https://www.cnblogs.com/justnow/p/4362891.html

QQ揭秘:如何实现窗体靠边隐藏?【低调赠送:QQ高仿版GG 4.2 最新源码】相关推荐

  1. QQ揭秘:如何实现托盘闪动消息提醒?【低调赠送:QQ高仿版GG 4.1 最新源码】

    转载自:https://www.cnblogs.com/justnow/p/4195142.html 当QQ收到好友的消息时,托盘的图标会变成好友的头像,并闪动起来,点击托盘,就会弹出与好友的聊天框, ...

  2. 如何做到在虚拟数据库和真实数据库之间自由切换?【低调赠送:QQ高仿版GG 4.4 最新源码】...

    记得以前在公司上班时,有时候白天的活没干完,我就会把工作带回家晚上加班继续做.但是,我们开发用的数据库是部署在公司局网内部的一台服务器上的,在家里是肯定连不上这台机器的.在家里没有数据库,服务端就跑不 ...

  3. 可在广域网部署运行的QQ高仿版 -- GG叽叽(源码)

    前段时间看到园子里有朋友开发了QQ高仿版的程序,我也非常有兴趣,以前一直有个做即时聊天程序的梦,趁这段时间工作不是很忙,就开始动手来做这个事情.根据我以往积累下来的项目经验,实现QQ的基本功能,问题应 ...

  4. 【转】可在广域网部署运行的QQ高仿版 -- GG叽叽(源码)

    前段时间看到园子里有朋友开发了QQ高仿版的程序,我也非常有兴趣,以前一直有个做即时聊天程序的梦,趁这段时间工作不是很忙,就开始动手来做这个事情.根据我以往积累下来的项目经验,实现QQ的基本功能,问题应 ...

  5. 【C#】WPF和winform窗体贴边隐藏(类似QQ)

    [WPF]实现窗体贴边隐藏 1.新建WPF项目Test,主窗体MainWindow.xaml,在后台MainWindow.xaml.cs填写下面的代码.主窗体调用Hide类,实现隐藏功能. //有些引 ...

  6. jquery源码之低调的回调函数队列--Callbacks

    jQuery中有一个很实用的函数队列,可能我们很少用到,但他在jQuery内部却有着举足轻重的地位. 他就是Callbacks. jQuery作者用它构建了很多非常重要的模块.比如说$.Deferre ...

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

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

  8. C# 实现窗口程序winform像QQ一样靠近桌面边缘自动隐藏窗口

    实现原理: 实现这个功能的原理步骤如下: 1.判断窗体程序是否靠近桌面边缘: 2.获取桌面屏幕大小与窗体程序大小: 3.把窗体程序显示在桌面以外隐藏起来,预留部分窗体方便用户拉出程序: 4.判断鼠标是 ...

  9. 【C#+SQL Server】实现模仿QQ的交友软件 四:主窗体设计讲解(附源码和资源)

    需要源码和资源请点赞关注收藏后评论区留言私信~~~ 其他几个部分文章链接如下 [C#+SQL Server]实现模仿QQ的交友软件 一:系统简介.功能展示与数据库设计(附源码和资源) [C#+SQL ...

  10. QQ技术全攻略(原来简单的QQ,还隐藏着这么多秘密!)

    来源:http://blog.yesky.com/ QQ技术全攻略(原来简单的QQ,还隐藏着这么多秘密!) 1.将您的QQ的在线状态发布在互联网上 将您的QQ的在线状态发布在互联网上,不用加好友也可以 ...

最新文章

  1. 盘点几个值得你借鉴的Java学习方法
  2. iphone怎么长截屏_新iPhone又要为中国定制?除了价格,还有这些惊喜
  3. 防止API被恶意调用,一般有哪些方法?
  4. 高能解析得时候忽略某个字段_我们什么时候应该忽略批评?
  5. RedHat 5.6_x86_64 + ASM + RAW+ Oracle 10g RAC (二)
  6. c语言111111等于111 11,c语言第02章数据类型.ppt
  7. OCR身份证识别功能
  8. 企业常用OSPF组网配置示例
  9. apimanager-wso2-OKD-deploy
  10. linux上压缩pdf文件,如何压缩PDF文件?
  11. SPA单页面首屏加载慢怎么解决???
  12. 流量焦虑意外带来契机,“福禄控股们”赚钱容易做大难?
  13. reduceByKey
  14. Python 实现文本共现网络分析
  15. BUUCTF WEB [BJDCTF2020]ZJCTF,不过如此
  16. bp神经网络模式识别,bp神经网络数字识别
  17. python界面实现点餐系统_基于PythonFlask的网上点餐系统管理员后台开发
  18. python离线安装第三方包
  19. Linux(deepin) 解决 Anaconda 环境中 matplotlib 中文乱码问题
  20. msysgit安装及使用教程大全

热门文章

  1. 苹果手机速度慢_安卓日语App,苹果也看进来
  2. 中国运动草皮设备市场趋势报告、技术动态创新及市场预测
  3. 数字推理题的解题技巧
  4. [文章]Android不流畅,究其本质
  5. 事件解析树Drain3使用方法和解释
  6. 免费剪辑音乐的软件都有哪些?音频剪辑方法分享?
  7. python电影数据分析报告_Python进行电影数据分析及可视化
  8. 指针的类型(即指针本身的类型)和指针所指向的类型是两个概念
  9. 永中office linux卸载,ubuntu下完全彻底删除永中office的方法
  10. 测国外服务器速度的网站,美国服务器如何测试速度?