用过qq的同学都知道,qq主窗口在靠近界面边缘时会自动隐藏,而当鼠标再一次进入的时候会自动弹出,接下来我将记录下自己实现的类似同样的功能,支持多屏幕靠边隐藏。文章末尾我提供了demo的下载地址,这个样例我是从网上下载下来,并自己进行了优化,主要针对边界判断和多屏幕支持。
下面是我做的效果展示,由于录屏软件录制屏幕顶端不好录制,所以录制了屏幕左侧,我自己测试的结果是:屏幕左、屏幕上和屏幕右都没有问题。如果发现问题的同学可以联系我。
效果预览
接下来我将每一步的实现代码分别做以解释:
一、窗口移动
做windows桌面程序的同学,应该都会这个功能,不过我还是贴一下代码吧,虽然不是特别复杂。要实现这个功能只需要重写3个方法,分别是:mousePressEvent、mouseMoveEvent和mouseReleaseEvent。
1、mousePressEvent
1void FloatingWidget::mousePressEvent(QMouseEvent *e)2{3if (e->button() == Qt::LeftButton)4{5m_dragPosition = e->globalPos() - frameGeometry().topLeft();6e->accept();7}8}2、mouseMoveEvent
1voidFloatingWidget::mouseMoveEvent(QMouseEvent*event)2{3if(event->buttons()&Qt::LeftButton)4{5QPointpos=event->globalPos()-m_dragPosition;67QDesktopWidget*desktop=qApp->desktop();8QRectrect=desktop->screenGeometry(QCursor::pos());9QRectframeRect=frameGeometry();10if(rect.top()>=pos.y())//修正顶端位置11{12pos.setY(rect.top());13}1415if(rect.left()>=pos.x())//修正左侧位置16{17intleftScreenNumber=desktop->screenNumber(pos-QPoint(width(),0));18if(desktop->screenGeometry(leftScreenNumber).contains((pos-QPoint(width(),0)))==false)19{20pos.setX(rect.left());21}22}2324if(rect.right()<=pos.x()+frameRect.width())//修正右侧位置25{26intrightScreenNumber=desktop->screenNumber(pos+QPoint(width(),0));27if(desktop->screenGeometry(rightScreenNumber).contains((pos+QPoint(width(),0)))==false)28{29pos.setX(rect.right()-frameRect.width());30}31}32move(pos);3334event->accept();35}36}这个函数里有3个位置修正判断,主要实现了在鼠标拖拽时,保证窗口不移出屏幕。
3、mouseReleaseEvent
1void FloatingWidget::mouseReleaseEvent(QMouseEvent * event)2{3QWidget::mouseReleaseEvent(event);4}通过上述3个方式的重写,就实现了窗口的拖拽,并且我们的窗口是不能拖拽到屏幕意外
二、屏幕边界自动隐藏
窗口移动到屏幕边界时,自动隐藏我们的窗口,首先我们来考虑这么几个问题:
1、什么时候需要隐藏窗口
2、什么时候需要显示窗口
3、检测窗口是否需要隐藏
4、窗口显示时怎么回到起始位置
问题1:隐藏窗口在我们鼠标移除窗口的时候,这个时候需要注意,鼠标在屏幕边界时不能隐藏
问题2:鼠标进入到我们的窗口时
问题3:窗口的边界和屏幕对应(比如:窗口左边界对应屏幕左边界)边界如果距离小于我们制定的边界检测宽度则可以隐藏
问题4:记录平路隐藏时的位置,方便回显回去
搞清楚上述4个问题后,我们就来贴代码吧
1、首先是窗口隐藏
1voidFloatingWidget::leaveEvent(QEvent*e)2{3QPointmousePos=mapFromGlobal(QCursor::pos());4if(rect().contains(mousePos)==false5&&mousePos.x()!=rect().width())6{7HideDockWidget();8}9else10{11if(m_timer==nullptr)12{13m_timer=newQTimer(this);14connect(m_timer,&QTimer::timeout,this,[this]{15QPointmousePos=mapFromGlobal(QCursor::pos());16if(this->rect().contains(mousePos)==false17&&mousePos.x()!=rect().width())18{19HideDockWidget();20}21});22}23m_timer->start(500);24}2526QWidget::leaveEvent(e);27}鼠标移出窗口时,需要隐藏窗口,首先判断鼠标是否还在窗口内,包括窗口边界,如果在窗口内,则开启定时器,每隔500毫秒检测鼠标是否还在屏幕内,因为leaveEvent事件和enterEvent是成对出现的,当leaveEvent发生一次后,除非enterEvent触发,否则不会触发;如果不在窗口内,直接去隐藏窗口。
点击领取Qt学习资料+视频教程~「链接」
2、显示窗口
显示窗口就比较好理解了,只需要在鼠标进入窗口时,如果窗口之前隐藏了,则把窗口恢复到之前隐藏的位置
1void FloatingWidget::enterEvent(QEvent * e)2{3if (m_timer && m_timer->isActive())4{5m_timer->stop();6}78ShowDockWidget();910QWidget::enterEvent(e);11}3、检测窗口是否需要隐藏
1voidFloatingWidget::HideDockWidget()2{3if(m_IsVisible==false)4{5return;6}78m_IsVisible=false;910intcurHeight=height();11intcurWidth=width();1213QDesktopWidget*desktop=qApp->desktop();14QRectrect=desktop->screenGeometry(this);1516if(frameGeometry().left()-CHECK_BORDER<=rect.top()17&&TEST_BIT(m_feature,LeftArea))18{19MoveWindow(pos(),pos()-QPoint(curWidth-HIDE_BORDER,0));20}21elseif(frameGeometry().right()+CHECK_BORDER>=rect.right()22&&TEST_BIT(m_feature,RightArea))23{24MoveWindow(pos(),pos()+QPoint(curWidth-HIDE_BORDER,0));25}26elseif(frameGeometry().top()-CHECK_BORDER<=rect.top()27&&TEST_BIT(m_feature,TopArea))28{29MoveWindow(pos(),pos()-QPoint(0,curHeight-HIDE_BORDER));30}31else32{33m_IsVisible=true;34}3536if(m_IsVisible==false)37{38if(m_timer&&m_timer->isActive())39{40m_timer->stop();41}42}43}4、窗口回显到起始位置
1voidFloatingWidget::ShowDockWidget()2{3if(m_IsVisible)4{5return;6}78m_IsVisible=true;910intcurHeight=height();11intcurWidth=width();1213QDesktopWidget*desktop=qApp->desktop();14QRectrect=desktop->screenGeometry(this);15QRectframeRect=frameGeometry();1617if(frameRect.left()==m_RecoverPosition.x()-(curWidth-HIDE_BORDER)18&&TEST_BIT(m_feature,LeftArea))19{20MoveWindow(pos(),m_RecoverPosition);21}22elseif(frameRect.left()==m_RecoverPosition.x()+(curWidth-HIDE_BORDER)23&&TEST_BIT(m_feature,RightArea))24{25MoveWindow(pos(),m_RecoverPosition);26}27elseif(frameRect.top()==m_RecoverPosition.y()-(curHeight-HIDE_BORDER)28&&TEST_BIT(m_feature,TopArea))29{30MoveWindow(pos(),m_RecoverPosition);31}32else33{34m_IsVisible=false;35}36}5、最后是窗口移动算法
1voidFloatingWidget::MoveWindow(constQPoint&start,constQPoint&end,unsignedintstep)2{3QPointdistance=end-start;4QPointstepPos,stepOne;5if(end.x()==start.x())6{7stepOne.setY(step*(distance.y()>0?1 :-1));8}9else10{11stepOne.setX(step*(distance.x()>0?1 :-1));12}13stepPos=stepOne;1415intdisLenght=distance.manhattanLength();16while(stepPos.manhattanLength()<=disLenght)17{18move(start+stepPos);19stepPos+=stepOne;20}2122move(end);2324m_RecoverPosition=start;25}参数分别是:起始位置、终点位置和每次移动距离
转载:https://www.cnblogs.com/swarmbees/p/5926144.html
作者:朝十晚八orTwowords
免责声明:内容来自用户上传并发布,站点仅提供信息存储空间服务,不拥有所有权,本网站所提供的信息只供参考之用。