首页 > 编程语言 >C# wpf 实现窗口靠近屏幕边缘自动吸附

C# wpf 实现窗口靠近屏幕边缘自动吸附

时间:2023-08-28 14:57:52浏览次数:48  
标签:鼠标 C# private int 屏幕 wpf public rect Left

参考:https://blog.csdn.net/qq_35831134/article/details/88751067

#region 侧吸
        private new bool Hide = false;       //用来表示当前隐藏状态,例如Hide=false就是不在隐藏状态
        string type = "";                   //用来表示窗口隐藏在哪个方向
        private void SliderTimer_Tick(object sender, EventArgs e)   
        {
            //this.TopMost = false;        //窗体不显示在所有软件最前面
            int dif = 20;
            Mouses.POINT mp = new Mouses.POINT();//获得当前鼠标位置 
            Mouses.GetCursorPos(out mp);
            Point pt = new Point(mp.X, mp.Y);
            System.Windows.Forms.Screen screen = System.Windows.Forms.Screen.PrimaryScreen;
            int width = screen.Bounds.Width;            //获取屏幕的宽度     
            int height = screen.Bounds.Height;          //获取屏幕的高度
            if (!this.RestoreBounds.Contains(pt))       //判断鼠标是否在窗体内 
            {
                //如果不在窗体内
                if (Hide == false)
                {
                    if (this.Left < 10)           //窗口左边碰到屏幕最左边
                    {
                        this.Left = -this.Width + 3;    //隐藏窗口,窗口宽度加3取反(为负数)
                        Hide = true;
                        type = "left";                  //窗口隐藏在左边
                    }
                    else if (width - this.Left - this.Width < 10)//窗口右边碰到屏幕最右边
                    {
                        this.Left = width - 3;            //隐藏窗口,窗口宽度加3取反(为负数)
                        Hide = true;
                        type = "right";                 //窗口隐藏在右边
                    }
                    else if (this.Top < 10)      //窗口上边碰到屏幕最上边
                    {
                        this.Top = -this.Height + 3;    //隐藏窗口,窗口高度加3取反(为负数)
                        Hide = true;
                        type = "up";                    //窗口隐藏在上边
                    }
                }
            }
            else
            {    //如果在窗体内
                if (this.Left > dif && type == "left")
                {
                    Hide = false;
                }
                else if (width - this.Left - this.Width > dif && type == "right")
                {
                    Hide = false;
                }
                else if (this.Top > dif && type == "up")
                {
                    Hide = false;
                }
                //如果在窗体内且之前是隐藏状态
                if (Hide == true)
                {
                    this.Topmost = true;        //窗体显示在所有软件最前面
                    if (type == "left")
                    {
                        this.Left = 0;
                        Hide = false;
                    }
                    else if (type == "right")
                    {
                        this.Left = width - this.Width;
                        Hide = false;
                    }
                    else if (type == "up")
                    {
                        this.Top = 0;
                        Hide = false;
                    }
                }
            }
        }
       
        private DispatcherTimer SlideTimer;

        private void EnableSlider()
        {
            this.SlideTimer = new DispatcherTimer();
            this.SlideTimer.Tick += SliderTimer_Tick;
            this.SlideTimer.Interval = TimeSpan.FromMilliseconds(10);
            this.SlideTimer.Start();
            this.SizeChanged += (o, e) =>
            {
                if (this.WindowState == WindowState.Minimized)
                {
                    this.SlideTimer.Stop();
                }
                else if (this.WindowState == WindowState.Normal)
                {
                    this.SlideTimer.Start();
                }
            };
        }
        #endregion

 

 

【出处】:https://blog.csdn.net/weixin_53370274/article/details/122843287

=======================================================================================

wpf仿qq边缘自动停靠,支持多屏

  wpf完全模仿qq边缘自动隐藏功能,采用鼠标钩子获取鼠标当前状态,在通过当前鼠标的位置和点击状态来计算是否需要隐藏。

  以下是实现的具体方法:

一、鼠标钩子实时获取当前鼠标的位置和点击状态

    /// <summary>
    /// 鼠标全局钩子
    /// </summary>
    public class MouseHook
    {
        private const int WM_MOUSEMOVE = 0x200;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_RBUTTONDOWN = 0x204;
        private const int WM_MBUTTONDOWN = 0x207;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_RBUTTONUP = 0x205;
        private const int WM_MBUTTONUP = 0x208;
        private const int WM_LBUTTONDBLCLK = 0x203;
        private const int WM_RBUTTONDBLCLK = 0x206;
        private const int WM_MBUTTONDBLCLK = 0x209;

        /// <summary>
        /// 点
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public class POINT
        {
            public int x;
            public int y;
        }

        /// <summary>
        /// 钩子结构体
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public class MouseHookStruct
        {
            public POINT pt;
            public int hWnd;
            public int wHitTestCode;
            public int dwExtraInfo;
        }

        public const int WH_MOUSE_LL = 14; // mouse hook constant

        // 装置钩子的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

        // 卸下钩子的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);

        // 下一个钩挂的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);
        // 全局的鼠标事件
        public event MouseEventHandler onm ouseActivity;

        // 钩子回调函数
        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

        // 声明鼠标钩子事件类型
        private HookProc _mouseHookProcedure;
        private static int _hMouseHook = 0; // 鼠标钩子句柄

        /// <summary>
        /// 构造函数
        /// </summary>
        public MouseHook()
        {

        }

        /// <summary>
        /// 析构函数
        /// </summary>
        ~MouseHook()
        {
            Stop();
        }

        /// <summary>
        /// 启动全局钩子
        /// </summary>
        public void Start()
        {
            // 安装鼠标钩子
            if (_hMouseHook == 0)
            {
                // 生成一个HookProc的实例.
                _mouseHookProcedure = new HookProc(MouseHookProc);
                ProcessModule cModule = Process.GetCurrentProcess().MainModule;

                var mh = GetModuleHandle(cModule.ModuleName);
                _hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, _mouseHookProcedure,mh,0);

                //如果装置失败停止钩子
                if (_hMouseHook == 0)
                {
                    Stop();
                    throw new Exception("SetWindowsHookEx failed.");
                }
            }
        }

        /// <summary>
        /// 停止全局钩子
        /// </summary>
        public void Stop()
        {
            bool retMouse = true;

            if (_hMouseHook != 0)
            {
                retMouse = UnhookWindowsHookEx(_hMouseHook);
                _hMouseHook = 0;
            }

            // 如果卸下钩子失败
           // if (!(retMouse))
              //  throw new Exception("UnhookWindowsHookEx failed.");
        }
        int isUp = 0;
        /// <summary>
        /// 鼠标钩子回调函数
        /// </summary>
        private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            try
            {
                // 如果正常运行并且用户要监听鼠标的消息
                if ((nCode >= 0) && (OnMouseActivity != null))
                {
                    MouseButtons button = MouseButtons.None;
                    int clickCount = 0;
                    switch (wParam)
                    {
                        case WM_LBUTTONDOWN:
                            button = MouseButtons.Left;
                            clickCount = 1;
                            isUp = 1;
                            break;
                        case WM_LBUTTONUP:
                            button = MouseButtons.Left;
                            clickCount = 1;
                            isUp = 2;
                            break;
                        case WM_LBUTTONDBLCLK:
                            button = MouseButtons.Left;
                            clickCount = 2;
                            break;
                        case WM_RBUTTONDOWN:
                            button = MouseButtons.Right;
                            clickCount = 1;
                            isUp = 1;
                            break;
                        case WM_RBUTTONUP:
                            button = MouseButtons.Right;
                            clickCount = 1;
                            isUp = 2;
                            break;
                        case WM_RBUTTONDBLCLK:
                            button = MouseButtons.Right;
                            clickCount = 2;
                            break;
                            default:
                            if (isUp == 2) isUp = 0;
                            break;
                    }

                    // 从回调函数中得到鼠标的信息
                    MouseHookStruct MyMouseHookStruct =
                        (MouseHookStruct) Marshal.PtrToStructure(lParam, typeof (MouseHookStruct));
                    var x = MyMouseHookStruct.pt.x;
                    var y = MyMouseHookStruct.pt.y;
                    MouseEventArgs e = new MouseEventArgs(button, clickCount, x,  y, isUp);

                    // 如果想要限制鼠标在屏幕中的移动区域可以在此处设置
                    // 后期需要考虑实际的x、y的容差
                    if (!Screen.PrimaryScreen.Bounds.Contains(e.X, e.Y))
                    {
                        //return 1;
                    }

                    onm ouseActivity(this, e);
                }



            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }


            // 启动下一次钩子
            return CallNextHookEx(_hMouseHook, nCode, wParam, lParam);
        }
    }
钩子程序

二、判断窗口是否在屏幕边缘

  如果是在屏幕边缘,并且鼠标离开窗体,那么就需要隐藏窗口

        /// <summary>
        /// 检测是否需要隐藏窗体
        /// </summary>
        /// <param name="e"></param>
        /// <param name="rect"></param>
        private void CheckIsHide(MouseEventArgs e,System.Drawing.Rectangle rect)
        {
            var x = e.X;
            var y = e.Y;
            if (x < rect.Left) x = rect.Left;
            if (x > rect.Right) x = rect.Right;
            if (y < rect.Top) y = rect.Top;
            if (y > rect.Bottom) y = rect.Bottom;

            bool isLeave = !(x >= this.Left && x <= (this.Left + this.ActualWidth) &&
                             y >= this.Top && y <= this.Top + this.ActualHeight);
            if (!isLeave)
            {
                //鼠标在窗体内移动时解除双击状态
                _isNoticefyShow = false;
                return;
            }
            //isLeave=true
            if (_isNoticefyShow == false)
            {
                //顶部判断
                 if (this.Top - _border < rect.Top)
                {
                    SetIsHide(true,rect);
                    //这里修正高度为边界高度,这样做的原因主要是避免鼠标移动到边框上面时出现闪动
                    _oldTop = rect.Top;
                    UpdateLeft(rect);
                }
                //左边判断
                 else if (this.Left - _border < rect.Left)
                {
                    SetIsHide(true, rect);
                    //这里修正左边
                    _oldLeft = rect.Left;
                    this.Left = rect.Left - this.ActualWidth;
                    UpdateTop(rect);
                }
                //右边判断
                else if (this.Left+this.ActualWidth + _border > rect.Right)
                {
                    SetIsHide(true, rect);
                    //修正右边
                    _oldLeft = rect.Right - this.ActualWidth;
                    this.Left = rect.Right;
                   UpdateTop(rect);
                }
            }
        }
检测是否需要隐藏窗口

三、窗口隐藏时根据鼠标位置判断是否需要显示

  如果鼠标在边框位置,并且进入了上次窗体隐藏的边框内,那么就显示窗体

        /// <summary>
        /// 判断鼠标时候在窗体边缘
        /// </summary>
        /// <returns></returns>
        private bool CheckMouseIsWindowBorder(MouseEventArgs e, System.Drawing.Rectangle rect)
        {
            //获取边界的值
            //判断top
            if (e.Y - _border <= rect.Top && e.X >= this.Left && e.X <= (this.Left + this.ActualWidth))
            {
                return true;
            }
            //判断left
            if (e.X - _border<=rect.Left && e.Y >= this.Top && e.Y <= (this.Top + this.ActualHeight))
            {
                //显示
                return true;
            }
            //判断right
            if (this.Left > rect.Left + _border && e.X  + _border >= rect.Right && e.Y >= this.Top &&
                e.Y <= (this.Top + this.ActualHeight))
            {
                return true;
            }

            //SystemInformation.VirtualScreen.
            //判断右边
            return false;
        }
判断鼠标是否在窗体边缘

四、双击托盘图标显示窗体

  显示窗体简单,直接展示就可以,关键是要实现窗体显示后如果窗体还在屏幕边框位置,那么需要判断什么情况下需要隐藏窗体,现在有以下两种情况需要隐藏:

  1.鼠标在离开任务栏后经过窗口后在离开窗口,窗口需要自动隐藏

  2.鼠标在离开任务栏后在窗口外的其它位置点击,触发窗口自动隐藏

  1情况容易,在进入窗体时清空托盘图标点击的标记就可以了

  2情况处理有点麻烦,由于在窗口外的其他位置点击这个事件在双击托盘图标的时候也会触发,我们要屏蔽掉这时这个触发条件,只有在托盘外面时去点击才有效,具体的方案是,在鼠标从托盘移动时才标记点击事件有效,这样就可以避免顺序错乱了,部分代码如下;

  (1).在双击托盘图标时标记状态:

_isNoticefyShow = true;
_isCanSet = false;
View Code

  (2).鼠标双击后,移动

                if (e.Delta == 0 && _isNoticefyShow && _isCanSet == false)
                {
                    //鼠标双击后,移动,并且没有设置
                    _isCanSet = true;
                    return;
                }
View Code

  (3).在鼠标移除托盘图标后,点击鼠标后,接触托盘双击状态

                if ((e.Delta == 1 || e.Delta == 2) && _isNoticefyShow && _isCanSet)
                {
                    _isNoticefyShow = false;
                    CheckIsHide(e,rect);
                    return;
                }        
View Code

 

具体的实现demo地址如下:

https://gitee.com/sczmzx/WindowAutoHide

 

【出处】:https://www.cnblogs.com/sczmzx/p/8996371.html

=======================================================================================

 

标签:鼠标,C#,private,int,屏幕,wpf,public,rect,Left
From: https://www.cnblogs.com/mq0036/p/17662246.html

相关文章

  • 手动删除anaconda中的库
    1、找到anaconda目录下pkgs文件夹查看是否有要删除的包,如果有则直接删除。2、在anaconda目录下找到lib/python3.X/site_packages,查看此文件夹里是否包含要删除的包,如果有直接删除。3、在anaconda目录下找到conda-meta文件夹,查看此文件夹是否包含要删除的包的名称,如果有则直接删......
  • activiti 删除某个流程的sql
    DELETEFROMACT_HI_ATTACHMENTWHEREPROC_INST_ID_='152512';DELETEFROMACT_HI_COMMENTWHEREPROC_INST_ID_='152512';DELETEFROMACT_HI_ACTINSTWHEREPROC_INST_ID_='152512';DELETEFROMACT_HI_DETAILWHEREPROC_INST_ID_=......
  • @Resource与@Autowired注解的区别
    前言1、什么是byName和byType简单来说,byName就是根据变量名去匹配bean的id属性,而byType则是根据变量类型去匹配bean的class属性。实例说明:<beanid="userService"class="com.test.UserServiceImpl"></bean>@AutowiredprivateUserServiceuserService;此处byName就是拿变量名us......
  • ConcurrentHashMap为何不能插入null?HashMap为何可以?
    归纳来说就是两个问题:1.ConcurrentHashMap为什么key和value不能为null?2.ConcurrentHashMap能保证复合操作的原子性吗?1.ConcurrentHashMap为什么key和value不能为null?ConcurrentHashMap的key和value不能为null主要是为了避免二义性。null是一个特殊的值,表示......
  • anaconda命令手册
    如何在conda中删除环境https://www.python100.com/html/6F19GKG4SB48.htmlanaconda环境切换https://zhuanlan.zhihu.com/p/583034130condaenvlist切换到想要的虚拟环境,如my_envcondaactivatemy_env删除虚拟环境condaenvremove--my_env命令列表condaisatool......
  • Js操作Select大全(取值、设置选中等等)
    Js操作Select大全(取值、设置选中等等) jquery操作select(取值,设置选中)每一次操作select的时候,总是要出来翻一下资料,不如自己总结一下,以后就翻这里了。比如<selectclass="selector"></select>1、设置value为pxx的项选中$(".selector").val("pxx");2、设置text为pxx的项选中$......
  • .net core Api获取所有Action以及注释内容
    有个项目需要获取项目内所有Action,并在凌晨定时任务跑完所有接口检查是否有接口报错,写了如下方法:///<summary>///获取Action注释///</summary>///<paramname="root"></param>///<paramname="method">方法</para......
  • Adobe Audition 2023(au2023)Mac+win中文永久使用版
    AdobeAudition2023是音频编辑软件AdobeAudition的最新版本,也是目前市场上最强大的音频编辑软件之一。它不仅拥有强大的音频编辑功能,还具备自动音频处理功能和高质量音频重建技术,为用户带来更为丰富的音频处理体验。→→↓↓载AdobeAudition2023 强大的音频处理功能在Ado......
  • 为WPF按钮添加UAC盾牌图标
    在上一篇文章中,介绍了如何获取系统Shell的图标。在C#中调用SHGetStockIconInfo即可获取获取图标 定义SHGetStockIconInfo函数用到的数据结构1publicenumSHSTOCKICONID:uint2{3///<summary>Documentofatypewithnoassociatedapplicatio......
  • web2.0技术-css兼容IE6/IE7/FF的通用方法
    一、CSSHACK以下两种方法几乎能解决现今所有HACK.1,!important随着IE7对!important的支持,!important方法现在只针对IE6的HACK.(注意写法.记得该声明位置需要提前.)<style>#wrapper{width:100px!important;/*IE7+FF*/width:80px......