窗口靠边自动隐藏

用过qq的同学都知道,qq主窗口在靠近界面边缘时会自动隐藏,而当鼠标再一次进入的时候会自动弹出,接下来我将记录下自己实现的类似同样的功能,支持多屏幕靠边隐藏。文章末尾我提供了demo的下载地址,这个样例我是从网上下载下来,并自己进行了优化,主要针对边界判断多屏幕支持

下面是我做的效果展示,由于录屏软件录制屏幕顶端不好录制,所以录制了屏幕左侧,我自己测试的结果是:屏幕左、屏幕上和屏幕右都没有问题。如果发现问题的同学可以联系我。

效果预览

接下来我将每一步的实现代码分别做以解释:

一、窗口移动

做windows桌面程序的同学,应该都会这个功能,不过我还是贴一下代码吧,虽然不是特别复杂。要实现这个功能只需要重写3个方法,分别是:mousePressEvent、mouseMoveEvent和mouseReleaseEvent。

1、mousePressEvent

1 void FloatingWidget::mousePressEvent(QMouseEvent *e)
2 {
3     if (e->button() == Qt::LeftButton)
4     {
5         m_dragPosition = e->globalPos() - frameGeometry().topLeft();
6         e->accept();
7     }
8 }

2、mouseMoveEvent

 1 void FloatingWidget::mouseMoveEvent(QMouseEvent * event)
 2 {
 3     if (event->buttons() & Qt::LeftButton)
 4     {
 5         QPoint pos = event->globalPos() - m_dragPosition;
 6
 7         QDesktopWidget * desktop = qApp->desktop();
 8         QRect rect = desktop->screenGeometry(QCursor::pos());
 9         QRect frameRect = frameGeometry();
10         if (rect.top() >= pos.y())//修正顶端位置
11         {
12             pos.setY(rect.top());
13         }
14
15         if (rect.left()>= pos.x())//修正左侧位置
16         {
17             int leftScreenNumber = desktop->screenNumber(pos - QPoint(width(), 0));
18             if (desktop->screenGeometry(leftScreenNumber).contains((pos - QPoint(width(), 0))) == false)
19             {
20                 pos.setX(rect.left());
21             }
22         }
23
24         if (rect.right() <= pos.x() + frameRect.width())//修正右侧位置
25         {
26             int rightScreenNumber = desktop->screenNumber(pos + QPoint(width(), 0));
27             if (desktop->screenGeometry(rightScreenNumber).contains((pos + QPoint(width(), 0))) == false)
28             {
29                 pos.setX(rect.right() - frameRect.width());
30             }
31         }
32         move(pos);
33
34         event->accept();
35     }
36 }

这个函数里有3个位置修正判断,主要实现了在鼠标拖拽时,保证窗口不移出屏幕。

3、mouseReleaseEvent

1 void FloatingWidget::mouseReleaseEvent(QMouseEvent * event)
2 {
3     QWidget::mouseReleaseEvent(event);
4 }

通过上述3个方式的重写,就实现了窗口的拖拽,并且我们的窗口是不能拖拽到屏幕意外

二、屏幕边界自动隐藏

窗口移动到屏幕边界时,自动隐藏我们的窗口,首先我们来考虑这么几个问题:

1、什么时候需要隐藏窗口

2、什么时候需要显示窗口

3、检测窗口是否需要隐藏

4、窗口显示时怎么回到起始位置

问题1:隐藏窗口在我们鼠标移除窗口的时候,这个时候需要注意,鼠标在屏幕边界时不能隐藏

问题2:鼠标进入到我们的窗口时

问题3:窗口的边界和屏幕对应(比如:窗口左边界对应屏幕左边界)边界如果距离小于我们制定的边界检测宽度则可以隐藏

问题4:记录平路隐藏时的位置,方便回显回去

搞清楚上述4个问题后,我们就来贴代码吧

1、首先是窗口隐藏

 1 void FloatingWidget::leaveEvent(QEvent * e)
 2 {
 3     QPoint mousePos = mapFromGlobal(QCursor::pos());
 4     if (rect().contains(mousePos) == false
 5         && mousePos.x() != rect().width())
 6     {
 7         HideDockWidget();
 8     }
 9     else
10     {
11         if (m_timer == nullptr)
12         {
13             m_timer = new QTimer(this);
14             connect(m_timer, &QTimer::timeout, this, [this]{
15                 QPoint mousePos = mapFromGlobal(QCursor::pos());
16                 if (this->rect().contains(mousePos) == false
17                     && mousePos.x() != rect().width())
18                 {
19                     HideDockWidget();
20                 }
21             });
22         }
23         m_timer->start(500);
24     }
25
26     QWidget::leaveEvent(e);
27 }

鼠标移出窗口时,需要隐藏窗口,首先判断鼠标是否还在窗口内,包括窗口边界,如果在窗口内,则开启定时器,每隔500毫秒检测鼠标是否还在屏幕内,因为leaveEvent事件和enterEvent是成对出现的,当leaveEvent发生一次后,除非enterEvent触发,否则不会触发;如果不在窗口内,直接去隐藏窗口。

2、显示窗口

显示窗口就比较好理解了,只需要在鼠标进入窗口时,如果窗口之前隐藏了,则把窗口恢复到之前隐藏的位置

 1 void FloatingWidget::enterEvent(QEvent * e)
 2 {
 3     if (m_timer && m_timer->isActive())
 4     {
 5         m_timer->stop();
 6     }
 7
 8     ShowDockWidget();
 9
10     QWidget::enterEvent(e);
11 }

3、检测窗口是否需要隐藏

 1 void FloatingWidget::HideDockWidget()
 2 {
 3     if (m_IsVisible == false)
 4     {
 5         return;
 6     }
 7
 8     m_IsVisible = false;
 9
10     int curHeight = height();
11     int curWidth = width();
12
13     QDesktopWidget * desktop = qApp->desktop();
14     QRect rect = desktop->screenGeometry(this);
15
16     if (frameGeometry().left() - CHECK_BORDER <= rect.top()
17         && TEST_BIT(m_feature, LeftArea))
18     {
19         MoveWindow(pos(), pos() - QPoint(curWidth - HIDE_BORDER, 0));
20     }
21     else if (frameGeometry().right() + CHECK_BORDER >= rect.right()
22         && TEST_BIT(m_feature, RightArea))
23     {
24         MoveWindow(pos(), pos() + QPoint(curWidth - HIDE_BORDER, 0));
25     }
26     else if (frameGeometry().top() - CHECK_BORDER <= rect.top()
27         && TEST_BIT(m_feature, TopArea))
28     {
29         MoveWindow(pos(), pos() - QPoint(0, curHeight - HIDE_BORDER));
30     }
31     else
32     {
33         m_IsVisible = true;
34     }
35
36     if (m_IsVisible == false)
37     {
38         if (m_timer && m_timer->isActive())
39         {
40             m_timer->stop();
41         }
42     }
43 }

4、窗口回显到起始位置

 1 void FloatingWidget::ShowDockWidget()
 2 {
 3     if (m_IsVisible)
 4     {
 5         return;
 6     }
 7
 8     m_IsVisible = true;
 9
10     int curHeight = height();
11     int curWidth = width();
12
13     QDesktopWidget * desktop = qApp->desktop();
14     QRect rect = desktop->screenGeometry(this);
15     QRect frameRect = frameGeometry();
16
17     if (frameRect.left() == m_RecoverPosition.x() - (curWidth - HIDE_BORDER)
18         && TEST_BIT(m_feature, LeftArea))
19     {
20         MoveWindow(pos(), m_RecoverPosition);
21     }
22     else if (frameRect.left() == m_RecoverPosition.x() + (curWidth - HIDE_BORDER)
23         && TEST_BIT(m_feature, RightArea))
24     {
25         MoveWindow(pos(), m_RecoverPosition);
26     }
27     else if (frameRect.top() == m_RecoverPosition.y() - (curHeight - HIDE_BORDER)
28         && TEST_BIT(m_feature, TopArea))
29     {
30         MoveWindow(pos(), m_RecoverPosition);
31     }
32     else
33     {
34         m_IsVisible = false;
35     }
36 }

5、最后是窗口移动算法

 1 void FloatingWidget::MoveWindow(const QPoint & start, const QPoint & end, unsigned int step)
 2 {
 3     QPoint distance = end - start;
 4     QPoint stepPos, stepOne;
 5     if (end.x() == start.x())
 6     {
 7         stepOne.setY(step * (distance.y() > 0 ? 1 : -1));
 8     }
 9     else
10     {
11         stepOne.setX(step * (distance.x() > 0 ? 1 : -1));
12     }
13     stepPos = stepOne;
14
15     int disLenght = distance.manhattanLength();
16     while (stepPos.manhattanLength() <= disLenght)
17     {
18         move(start + stepPos);
19         stepPos += stepOne;
20     }
21
22     move(end);
23
24     m_RecoverPosition = start;
25 }

参数分别是:起始为孩子、目标位置和每次移动距离

demo下载链接:http://download.csdn.net/detail/qq_30392343/9644654

时间: 2024-10-13 20:37:06

窗口靠边自动隐藏的相关文章

WPF窗口长时间无人操作鼠标自动隐藏

原文:WPF窗口长时间无人操作鼠标自动隐藏 在软件开发中有时会有等待一段时间无人操作后隐藏鼠标,可能原因大致如下: 1.为了安全性,特别是那些需要用到用户名和密码登录服务端的程序,常常考虑长期无人操作,程序自动跳转到用户登录界面: 2.软件为了更好的播放效果,需要隐藏鼠标. 这里写的是第二种情况,wpf做播放时,需要隐藏鼠标. 思路是:假如3s鼠标不动则隐藏,设计了计时器的间隔时间为1s,并添加鼠标没移动的计数器,计数器达到3才执行程序.实现是这样的:每隔1s检测鼠标是否移动,如果不移动则计数器

【Iterm2】如何解决iterm2窗口自动隐藏的问题

一.问题描述 当我们使用Iterm2的Hotkey Windom功能时,通过快捷键唤起Iterm2窗口后,然后鼠标在iterm2窗口之外触发点击操作就会让 iterm2窗口自动隐藏.. 这样有时候会觉的很方便. 二.解决步骤 1)步骤1:进入热键配置 2)步骤2:勾选选项 pin hotkey window (stays open on loss of keyboard focus) 即销热键窗口 (在失去键盘焦点时保持打开状态)  原文地址:https://www.cnblogs.com/75

悬浮窗口(智能隐藏和显示)的一种实现方案

悬浮窗口应该具有的特性 为了实现让用户能方便打开软件主窗口,又不对用户界面造成明显的视觉干扰,悬浮窗口应该有以下特点: 和主窗口是二选一的关系,主窗口显示时自动隐藏,主窗口被全部遮挡时自动显示 始终置前,不被其它窗口遮挡,全屏播放电影.截图软件截图等情形时,取消置前. 支持全窗口拖动 半透明效果,鼠标移上时全为不透明 为了使隐藏和出现不显得突兀,支持淡入淡出效果 点击悬浮窗时,呼出主窗口,并隐藏悬浮窗口 上述特点的实现方案 整个实现方案依赖于主窗口内的一个定时器(200ms),定时检查主窗口的显

配置了iptux的“启动后主面板自动隐藏”的后果和处理

我的个人博客( 肥龙的博客)发表了新文章了! 欢迎大家过来阅读,以下是文章的连接地址 http://www.comingcode.com/?p=450 这段时间都是比较多使用ubuntu来工作了,主要是因为做摄像头数据的获取,这个处理是计划放在后台hadoop集群机器上的,所以需要编译linux版本,因此就顺带使用linux来工作了. 从windows切换到linux,还是很难改变windows的操作习惯,包命令和软件,但是现在已经安装了wineqq,同时也用wine安装了rtx,目前还是比较正

状态栏自动隐藏

一,经历 1> Bug 详情===>在某个控制器中, push了一个新控制器,新控制器的状态栏总会自动隐藏,有时候是点击的时候隐藏. 2> 我于是就在控制器的 view 显示的时候,显示状态栏,结果还是会在多次点击屏幕空白处时隐藏状态栏. 3> 我验证了 viewdidappear 那几个方法执行的先后顺序,还是发现不出来,哪个地方隐藏了状态栏. 我在不同的地方显示状态栏,结果还是会隐藏. 汪洋补牢失败,我就开始下面的探索... 4> 感觉像是下面的控制器接收到什么通知隐藏了

页面跳转 和虚拟键盘的自动隐藏

前提:起码要有两个视图控制器. 注意事项: 设置跳转的动画效果 UITextField输入时,虚拟键盘的位置设置(整体布局向上移动,虚拟键盘的自动隐藏) 实现的功能: A:在第一个页面跳转到第二个页面,然后第二个页面点击按钮,进行返回 B:在第一个页面有一个text控件,点击一个按钮,传递到第二个页面,然后显示到第二个 页面的label上面: 效果展示: 步骤: 1.新建两个类,然后勾选xib,在AppDelegate的实现文件把其中的一个视图加载进去 //新建一个视图控制器 MainViewC

[菜鸟成长记]iOS开发自学笔记07-UITextField自动隐藏键盘

点击UITextField输入框后,软键盘默认情况下在结束输入后不会自动隐藏,目前总结了两种可以自动隐藏软键盘的方法: 第一种:通过响应UITextField对象的Did End On Exit事件,当点击默认软键盘的"Done"按钮或"Return"按钮会触发Did End On Exit 事件,通过编码实现来响应Did End On Exit事件来实现自动隐藏键盘 - (IBAction)TextFieldDidEndOnExit:(id)sender { [t

Jquery UI - DatePicker 在Dialog中无法自动隐藏的解决思路

通过Jquery UI Dialog模态展示如下的一个员工编辑页面,但是遇到一个奇怪的问题:点击Start Date的input元素后,其无法失去焦点.从而导致DatePicker控件在选择日期后无法自动隐藏. 解决思路:给DatePicker加上onSelect事件,在该事件中让Start Date的input元素的父元素获取焦点,这样DatePicker控件在选择日期后就自动隐藏.

关于C# 窗体自动隐藏和加载的问题

最近在写一个小项目,开发一个小程序配合其他软件使用,其中一款软件在使用工作时需要截图生成报告,此时不能有其他应用程式界面在显示器桌面显示,故需要自动隐藏和加载窗体,通过阅读Windows API实现了这一功能与大伙分享交流一下:原本C#自带Hide()和Show()方法:但是在项目开发时将窗体定义为静态类型:故无法通过this关键字来调用其对应的隐藏和显示窗体方法.这里通过Windows API提供的函数来实现,首先要获取当前运行窗体的句柄,方法如下: 定义一个全局变量 IntPtr Handl