窗口靠邊自動隱藏


    用過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. 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時通過修改本文達到有利於轉載者的目的。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM