上一篇博文【Qt之實現360安全衛士主界面(一)】講解了使用Qt對360安全衛士界面怎么進行分割、布局,如何自定義窗口以及設置窗口背景圓角等,最終形成了一個類似的主界面。但是界面卻不能移動,不能伸縮,不能雙擊最大化還原等;今天該博文就主要講解這三方面的功能,最終的效果和標准窗口的處理效果一致。效果如下圖所示:
一、移動主界面
移動主界面是通過按住鼠標左鍵進行標題欄拖動最終導致主界面移動;由於還有窗口伸縮功能,因此對於標題欄左部,頂部,右部應該騰出5像素空間給窗口伸縮功能使用,即鼠標移動到這5像素空間之內的話,鼠標形狀就會發生改變(暗示可以伸縮窗口);為什么只有標題欄騰出5像素空間,而其他部件(如工具欄、內容區域、狀態欄)就不需要了?因為只有標題欄部件重新實現了void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event);這三個事件;而主窗口也實現了它自己的這三個事件,為了防止界面移動和界面伸縮相沖突,所以留有5像素的空間為窗口伸縮功能使用;下面講解移動主界面的代碼實現:
總體思路是:鼠標按下時設置按下標識並保存按下點坐標;鼠標移動時,判斷是否按下(標識)然后獲得移動鼠標點的坐標,根據兩者的差值最后移動主界面即可;當然,鼠標釋放時肯定要重置按下標識。

//鼠標按下事件
void TitleBar::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
if(event->y()<VALUE_DIS||event->x()<VALUE_DIS||rect().width()-event->x()<5)
{
event->ignore();
return;
}
m_ptPress = event->globalPos();
m_bLeftButtonPress = true;
}
event->ignore();
}
//鼠標移動事件
void TitleBar::mouseMoveEvent(QMouseEvent *event)
{
if(m_bLeftButtonPress)
{
m_ptMove = event->globalPos();
//移動主窗口
MainWindow *pMainWindow = (qobject_cast<MainWindow *>(parent()));
pMainWindow->move(pMainWindow->pos()+m_ptMove-m_ptPress);
//重新設置m_ptPress;
m_ptPress = m_ptMove;
}
event->ignore();
}
//鼠標釋放事件
void TitleBar::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_bLeftButtonPress = false;
}
event->ignore();
}
注意,在事件的末尾要加上event->ignore();語句,因為標題欄是覆蓋在主界面部件之上的,所以事件傳遞是先傳遞給標題欄,標題欄完成該事件之后,應使用event->ignore();表示繼續將事件傳遞給其父對象(即主界面部件);
二、伸縮主界面
界面當然要可以伸縮,即窗口變大變小,這些也是由鼠標事件產生的,也是三個事件處理代碼;當鼠標移動到主界面內部周圍5像素時,改變鼠標形狀;當進行伸縮拖動時,根據拖動方向進行主界面的位置和大小設置即可。

//鼠標按下事件
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_ptPressGlobal = event->globalPos();
m_bLeftBtnPress = true;
}
}
//鼠標移動事件
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if(!m_bLeftBtnPress)
{
m_eDirection = PointValid(event->x(),event->y());
SetCursorStyle(m_eDirection);
}
else
{
int nXGlobal = event->globalX();
int nYGlobal = event->globalY();
SetDrayMove(nXGlobal,nYGlobal,m_eDirection);
m_ptPressGlobal =QPoint(nXGlobal,nYGlobal);
}
}
//鼠標釋放事件
void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_bLeftBtnPress = false;
m_eDirection = eNone;
}
}
//鼠標雙擊事件
void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && event->y()<= m_pTitleBar->height())
{
if(!m_bMaxWin)
{
m_rectRestoreWindow = geometry();
setGeometry(qApp->desktop()->availableGeometry());
}
else
{
setGeometry(m_rectRestoreWindow);
}
m_bMaxWin = !m_bMaxWin;
}
}
其中設置鼠標形狀的代碼如下:

//設置鼠標樣式
void MainWindow::SetCursorStyle(enum_Direction direction)
{
//設置上下左右以及右上、右下、左上、坐下的鼠標形狀
switch(direction)
{
case eTop:
case eBottom:
setCursor(Qt::SizeVerCursor);
break;
case eRight:
case eLeft:
setCursor(Qt::SizeHorCursor);
break;
case eTopRight:
case eBottomLeft:
setCursor(Qt::SizeBDiagCursor);
break;
case eRightBottom:
case eLeftTop:
setCursor(Qt::SizeFDiagCursor);
break;
default:
setCursor(Qt::ArrowCursor);
break;
}
}
伸縮窗口的位置信息設置代碼如下:

//設置鼠標拖動的窗口位置信息
void MainWindow::SetDrayMove(int nXGlobal,int nYGlobal,enum_Direction direction)
{
//計算偏差
int ndX = nXGlobal - m_ptPressGlobal.x();
int ndY = nYGlobal - m_ptPressGlobal.y();
//獲得主窗口位置信息
QRect rectWindow = geometry();
//判別方向
if(direction & eTop)
{
rectWindow.setTop(rectWindow.top()+ndY);
}
if(direction & eRight)
{
rectWindow.setRight(rectWindow.right()+ndX);
}
if(direction & eBottom)
{
rectWindow.setBottom(rectWindow.bottom()+ndY);
}
if(direction & eLeft)
{
rectWindow.setLeft(rectWindow.left()+ndX);
}
if(rectWindow.width()< minimumWidth() || rectWindow.height()<minimumHeight())
{
return;
}
//重新設置窗口位置為新位置信息
setGeometry(rectWindow);
}
三、雙擊最大化和還原
這個功能處理起來很簡單,只要重新實現void mouseDoubleClickEvent(QMouseEvent *event)事件即可並且限制有效范圍,即在不超過標題欄高度的像素空間范圍內雙擊才有效:

//鼠標雙擊事件
void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && event->y()<= m_pTitleBar->height())
{
if(!m_bMaxWin)
{
m_rectRestoreWindow = geometry();
setGeometry(qApp->desktop()->availableGeometry());
}
else
{
setGeometry(m_rectRestoreWindow);
}
m_bMaxWin = !m_bMaxWin;
}
}
使用QDesktopWidget類的availableGeometry()函數可排除任務欄(桌面)所占空間。