近期,做項目用到無邊框窗體,令人蛋疼的是無邊框窗體大小的改變要像右邊框那樣,上下左右四周,而且要流暢。
網上也找了些代碼,發現居然還要連接到windows事件,這顯然不合常理,后來自己新建了demo,寫了一個小時,問題太多了,扔一邊先不管了。
今天需要改進UI界面,沒辦法了,重新整理了下思路,沒想到做出來了。下面來分享下實現的過程,也許是菜鳥專欄,高手勿噴~
1.首先大家要了解各九宮格的概念
一個窗體可以被划分為上、下、左、右、左上、左下、右上、右下、中間,除了中間部分,其他都需要寫程序處理。
在程序中定義Padding 為2,並同時定義枚舉類型。
#define PADDING 2
enum Direction { UP=0, DOWN=1, LEFT, RIGHT, LEFTTOP, LEFTBOTTOM, RIGHTBOTTOM, RIGHTTOP, NONE };
2.定義一個方法,參數為鼠標目前的全局位置。
void Dialog::region(const QPoint &cursorGlobalPoint) {
// 獲取窗體在屏幕上的位置區域,tl為topleft點,rb為rightbottom點 QRect rect = this->rect(); QPoint tl = mapToGlobal(rect.topLeft()); QPoint rb = mapToGlobal(rect.bottomRight());
int x = cursorGlobalPoint.x(); int y = cursorGlobalPoint.y(); if(tl.x() + PADDING >= x && tl.x() <= x && tl.y() + PADDING >= y && tl.y() <= y) { // 左上角 dir = LEFTTOP; this->setCursor(QCursor(Qt::SizeFDiagCursor)); // 設置鼠標形狀 } else if(x >= rb.x() - PADDING && x <= rb.x() && y >= rb.y() - PADDING && y <= rb.y()) { // 右下角 dir = RIGHTBOTTOM; this->setCursor(QCursor(Qt::SizeFDiagCursor)); } else if(x <= tl.x() + PADDING && x >= tl.x() && y >= rb.y() - PADDING && y <= rb.y()) { //左下角 dir = LEFTBOTTOM; this->setCursor(QCursor(Qt::SizeBDiagCursor)); } else if(x <= rb.x() && x >= rb.x() - PADDING && y >= tl.y() && y <= tl.y() + PADDING) { // 右上角 dir = RIGHTTOP; this->setCursor(QCursor(Qt::SizeBDiagCursor)); } else if(x <= tl.x() + PADDING && x >= tl.x()) { // 左邊 dir = LEFT; this->setCursor(QCursor(Qt::SizeHorCursor)); } else if( x <= rb.x() && x >= rb.x() - PADDING) { // 右邊 dir = RIGHT; this->setCursor(QCursor(Qt::SizeHorCursor)); }else if(y >= tl.y() && y <= tl.y() + PADDING){ // 上邊 dir = UP; this->setCursor(QCursor(Qt::SizeVerCursor)); } else if(y <= rb.y() && y >= rb.y() - PADDING) { // 下邊 dir = DOWN; this->setCursor(QCursor(Qt::SizeVerCursor)); }else { // 默認 dir = NONE; this->setCursor(QCursor(Qt::ArrowCursor)); } }
3.在對話框類中定義幾個私有成員變量
bool isLeftPressDown; // 判斷左鍵是否按下 QPoint dragPosition; // 窗口移動拖動時需要記住的點
Direction dir; // 窗口大小改變時,記錄改變方向
編寫對話框構造函數,初始化幾個變量並做一些其他工作。
isLeftPressDown = false; this->dir = NONE; this->setMinimumHeight(100); this->setMinimumWidth(150); this->setWindowFlags(Qt::FramelessWindowHint|Qt::WindowSystemMenuHint); // 設置成無邊框對話框 this->setMouseTracking(true); // 追蹤鼠標 this->setStyleSheet("QDialog{background:url(:/bg_main.png)}"); // 設置樣式背景色,可有可無
4.接着就要實現幾個重要的重載事件了
void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event);
實現過程如下:
void Dialog::mouseReleaseEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { isLeftPressDown = false; if(dir != NONE) { this->releaseMouse(); this->setCursor(QCursor(Qt::ArrowCursor)); } } } void Dialog::mousePressEvent(QMouseEvent *event) { switch(event->button()) { case Qt::LeftButton: isLeftPressDown = true; if(dir != NONE) { this->mouseGrabber(); } else { dragPosition = event->globalPos() - this->frameGeometry().topLeft(); } break; case Qt::RightButton: this->close(); break; default: QDialog::mousePressEvent(event); } } void Dialog::mouseMoveEvent(QMouseEvent *event) { QPoint gloPoint = event->globalPos(); QRect rect = this->rect(); QPoint tl = mapToGlobal(rect.topLeft()); QPoint rb = mapToGlobal(rect.bottomRight()); if(!isLeftPressDown) { this->region(gloPoint); } else { if(dir != NONE) { QRect rMove(tl, rb); switch(dir) { case LEFT: if(rb.x() - gloPoint.x() <= this->minimumWidth()) rMove.setX(tl.x()); else rMove.setX(gloPoint.x()); break; case RIGHT: rMove.setWidth(gloPoint.x() - tl.x()); break; case UP: if(rb.y() - gloPoint.y() <= this->minimumHeight()) rMove.setY(tl.y()); else rMove.setY(gloPoint.y()); break; case DOWN: rMove.setHeight(gloPoint.y() - tl.y()); break; case LEFTTOP: if(rb.x() - gloPoint.x() <= this->minimumWidth()) rMove.setX(tl.x()); else rMove.setX(gloPoint.x()); if(rb.y() - gloPoint.y() <= this->minimumHeight()) rMove.setY(tl.y()); else rMove.setY(gloPoint.y()); break; case RIGHTTOP: rMove.setWidth(gloPoint.x() - tl.x()); rMove.setY(gloPoint.y()); break; case LEFTBOTTOM: rMove.setX(gloPoint.x()); rMove.setHeight(gloPoint.y() - tl.y()); break; case RIGHTBOTTOM: rMove.setWidth(gloPoint.x() - tl.x()); rMove.setHeight(gloPoint.y() - tl.y()); break; default: break; } this->setGeometry(rMove); } else { move(event->globalPos() - dragPosition); event->accept(); } } QDialog::mouseMoveEvent(event); }
到此為止,一個無邊框窗體拖動並且改變大小的功能就實現了,Run and debug it。
總結起來,這個算法其實並不復雜,就看有幾個點能不能想到:
1)窗體矩形區域要轉換成在屏幕上的區域,我采取的方式就是取TopLeft和RightBottom兩個點來確定這個區域。
2)鼠標移動要去全局的坐標。
3)region函數中判斷坐標區間,然后改變鼠標形狀,這塊很容易出錯,如果你一下子就寫出來,那我真的很佩服。
這個糾結的網上都沒有現成代碼的問題,終於在今天圓滿解決了。如需運行,請下載實例代碼:SizableNoFrame.rar
轉載請注明出處哦:http://www.cnblogs.com/xufeiyang/p/3313104.html