首页 > 代码库 > 窗口靠边自动隐藏

窗口靠边自动隐藏

    用过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     else10     {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) == false17                     && 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     else32     {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     else33     {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     else10     {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

窗口靠边自动隐藏