[仿QQ聊天工具系列一]关于停靠屏幕边缘时自动隐藏窗体的研究

      虽说腾讯公司的很多软件和游戏都是“参考”他人的,但它凭借着它庞大的用户量可以将该“山寨”版软件变成“官方”版,估计这是腾讯公司的一种战略方针,只要它拥有这么多的用户和资金,它就可以打垮这些软件归属的所谓的“官方”公司。不是每家公司都能做的像腾讯这么成功的,虽说我不是很苟同它的一部分“参考”文化,但它的成功是不可否认的。当然腾讯公司也有自己的创新,而且有些方面做的比所谓的“官方”软件好的多,如QQ就不必说了,还有QQ影音等等很多软件,虽然有些技术比不上其他公司的软件,但在用户体验方面做得非常好。用户体验是一款面向大众的好软件应该重点关注的方面,如果一款技术含量很高的软件,用户体验做得很糟糕,相信也不会有太多人想用。

      说了那么多,现在换我们来“参考”腾讯的聊天软件——QQ ,网上已经有很多高手做过聊天工具,但那个毕竟是别人的东西,想要进步还是得自己慢慢研究,加上一些的参考。写该文章只是希望记录下自己的研究足迹,高手莫拍砖,有错的地方也希望能指出,有什么需要改进的地方希望能指点,新入门的同志也可以多一份参考的资料。

      其实这个功能实现起来比较简单,只是有一些细节方面容易忽略而导致效果不是很好。在实现功能之前先把几个概念搞清楚,并且把一些关键的地方总结一下,并把坐标系统一:

1.窗体的客户区域(this.ClientRectangle):对于WinForm的窗体,窗体的客户区域是除掉窗体边界之后剩下的那部分区域,亦即将FormBorderStyle属性设置成None时所剩下的那部分。可以用Rectangle formRect=this.RectangleToScreen(this.ClientRectangle)来将this.ClientRectangle区域的Location属性的坐标系转换成屏幕坐标系,并用formRect来存储相对于屏幕坐标系的窗体客户区域。

2.客户区坐标系:该坐标系是以客户区的左上角为原点,是相对于客户区的逻辑坐标,可以用Point clientPoint=this.PointToClient(Point p)来将p坐标转换成客户区坐标系的坐标并返回给clientPoint。

3.屏幕坐标系:该坐标系是以显示屏的左上角为原点,是相对于屏幕的绝对坐标,可以用Point screenPoint=this.PointToScreen(Point p)来将p坐标转换成屏幕坐标系的坐标并返回给screenPoint。

4.获取鼠标光标的坐标:如果是鼠标事件中的话可以用e.Location来获取,其他情况可以用Cursor.Position或者Control.MousePoint来获取,经实验表明这几个属性获取的坐标都是相对于屏幕坐标系的,当然如果不放心可以用this.PointToScreen(Point p)方法将其转换成相对于屏幕坐标系的坐标

5.需要用到的事件:MouseMove鼠标事件,Move窗体事件,MouseLeave窗体事件,注意:MouseMove鼠标事件和MouseEnter窗体事件类似,都是进入窗体客户区才触发事件,窗体边界不属于窗体客户区,所在鼠标在边界处是无法触发事件的。对于MouseLeave窗体事件,如果鼠标移动到了窗体边界(如上所述边界不属于客户区),则相当于鼠标离开了窗体,则会触发该事件,如果窗体中有其它控件,则当鼠标移动到这些控件的时候也相当于鼠标离开了窗体,也会触发该事件,所以要考虑相应的情况来设置鼠标在一定范围内时不隐藏窗体,当鼠标离开该范围时且窗体this.Top等属性值小于某个值时,窗体可以自动隐藏。

6.无边界窗体和有边界窗体:QQ程序是无边界的,因此才可以做一些皮肤界面效果,对于无边界窗体,它是不可以拖动和改变大小的,除非自己定义事件来完成这些功能,这次研究的自动隐藏的窗体是有边界的(this.FormBorderStyle=FormBorderStyle.Sizable)。

7.定义自动隐藏枚举类型:

 internal  enum ShrinkType:byte

    {

        ShrinkNone=0,

        ShrinkTop,

        ShrinkBottom,

        ShrinkLeft,

        ShrinkRight

    }
本文只展示停靠屏幕上方时自动隐藏窗体,当鼠标移到该隐藏的窗体边缘时又会自动显示窗体,鼠标移开时又会自动隐藏窗体。屏幕其它方向的可类似实现。

下面为实现该功能的代码:     

       private void MainForm_Move(object sender, EventArgs e)

        {     

            if (this.Top == 0 )

            {

                this.Top = -this.Height+10;

                this.mShrink = ShrinkType.ShrinkTop;

            }          

        }



        private void MainForm_MouseMove(object sender, MouseEventArgs e)

        {

           

            switch (mShrink)

            {

                case ShrinkType.ShrinkTop:

                    {                      

                        this.Top = -2;                        

                        this.mShrink = ShrinkType.ShrinkNone;

                        break;

                    }

                default: break;

            }

        }



        private void MainForm_MouseLeave(object sender, EventArgs e)

        {

            if (ShrinkType.ShrinkNone==mShrink)

            {

                        if (this.Top <= 5)

                        {

                            Rectangle formRect =this.RectangleToScreen(this.ClientRectangle);

                            Point mousePoint = Cursor.Position;//Control.MousePosition;

                            if (mousePoint.Y<=formRect.Location.Y)

                            {

                                this.Top = -2;

                                return;

                            }

                            else if (mousePoint.X<=(formRect.Location.X-2)||mousePoint.X>=(formRect.Location.X+formRect.Width+2)||mousePoint.Y>=(formRect.Location.Y+formRect.Height+2))

                            {

                                this.Top = 0;

                            }

                        }

            }             

                 

        }

你可能感兴趣的:(qq)