• 窗口靠边自动隐藏


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

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

    ee

    效果预览

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

    一、窗口移动

        做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

    如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!! 

     

      


    很重要--转载声明

    1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
    2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。 

  • 相关阅读:
    Python使用MySQL数据库的方法以及一个实例
    【转载】关于Python中的yield
    利用KMeans聚类进行航空公司客户价值分析
    Python多线程编程
    搜索与排名思路整理
    两个UIView添加同一个手势只有最后一个有用
    缩放动画效果
    iOS通过UIAlertController弹出底部选择框来调用相机或者相册
    ios webview点击图片看大图效果及相应手势操作
    iOS开发:获取设备IP地址
  • 原文地址:https://www.cnblogs.com/swarmbees/p/5926144.html
Copyright © 2020-2023  润新知