From b7647f0b442c86f96f6a7dc1f5bee863f42c18bd Mon Sep 17 00:00:00 2001 From: feiyangqingyun Date: Mon, 5 Jul 2021 17:56:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- framelesswidget/framelesswidget.cpp | 157 +++++++++++++------------ framelesswidget/framelesswidget.h | 42 +++---- framelesswidget/framelesswidget2.cpp | 114 +++++++++++++----- framelesswidget/framelesswidget2.h | 19 +++ framelesswidget/frmframelesswidget.cpp | 16 ++- framelesswidget/frmframelesswidget.h | 2 +- framelesswidget/main.cpp | 3 + 7 files changed, 219 insertions(+), 134 deletions(-) diff --git a/framelesswidget/framelesswidget.cpp b/framelesswidget/framelesswidget.cpp index 8c852f8..f5934fa 100644 --- a/framelesswidget/framelesswidget.cpp +++ b/framelesswidget/framelesswidget.cpp @@ -9,15 +9,14 @@ FramelessWidget::FramelessWidget(QObject *parent) : QObject(parent) resizeEnable = true; widget = 0; - pressed = false; - pressedLeft = false; - pressedRight = false; - pressedTop = false; - pressedBottom = false; - pressedLeftTop = false; - pressedRightTop = false; - pressedLeftBottom = false; - pressedRightBottom = false; + mousePressed = false; + mousePoint = QPoint(0, 0); + mouseRect = QRect(0, 0, 0, 0); + + for (int i = 0; i < 8; ++i) { + pressedArea << false; + pressedRect << QRect(0, 0, 0, 0); + } //如果父类是窗体则直接设置 if (parent->isWidgetType()) { @@ -28,48 +27,62 @@ FramelessWidget::FramelessWidget(QObject *parent) : QObject(parent) bool FramelessWidget::eventFilter(QObject *watched, QEvent *event) { if (widget != 0 && watched == widget) { - if (event->type() == QEvent::Resize) { + if (event->type() == QEvent::WindowStateChange) { + //解决mac系统上无边框最小化失效的BUG +#ifdef Q_OS_MACOS + if (widget->windowState() & Qt::WindowMinimized) { + isMin = true; + } else { + if (isMin) { + //设置无边框属性 + widget->setWindowFlags(flags | Qt::FramelessWindowHint); + widget->setVisible(true); + isMin = false; + } + } +#endif + } else if (event->type() == QEvent::Resize) { //重新计算八个描点的区域,描点区域的作用还有就是计算鼠标坐标是否在某一个区域内 int width = widget->width(); int height = widget->height(); //左侧描点区域 - rectLeft = QRect(0, padding, padding, height - padding * 2); - //上侧描点区域 - rectTop = QRect(padding, 0, width - padding * 2, padding); + pressedRect[0] = QRect(0, padding, padding, height - padding * 2); //右侧描点区域 - rectRight = QRect(width - padding, padding, padding, height - padding * 2); + pressedRect[1] = QRect(width - padding, padding, padding, height - padding * 2); + //上侧描点区域 + pressedRect[2] = QRect(padding, 0, width - padding * 2, padding); //下侧描点区域 - rectBottom = QRect(padding, height - padding, width - padding * 2, padding); + pressedRect[3] = QRect(padding, height - padding, width - padding * 2, padding); //左上角描点区域 - rectLeftTop = QRect(0, 0, padding, padding); + pressedRect[4] = QRect(0, 0, padding, padding); //右上角描点区域 - rectRightTop = QRect(width - padding, 0, padding, padding); + pressedRect[5] = QRect(width - padding, 0, padding, padding); //左下角描点区域 - rectLeftBottom = QRect(0, height - padding, padding, padding); + pressedRect[6] = QRect(0, height - padding, padding, padding); //右下角描点区域 - rectRightBottom = QRect(width - padding, height - padding, padding, padding); + pressedRect[7] = QRect(width - padding, height - padding, padding, padding); } else if (event->type() == QEvent::HoverMove) { //设置对应鼠标形状,这个必须放在这里而不是下面,因为可以在鼠标没有按下的时候识别 QHoverEvent *hoverEvent = (QHoverEvent *)event; QPoint point = hoverEvent->pos(); if (resizeEnable) { - if (rectLeft.contains(point)) { + if (pressedRect.at(0).contains(point)) { widget->setCursor(Qt::SizeHorCursor); - } else if (rectRight.contains(point)) { + } else if (pressedRect.at(1).contains(point)) { widget->setCursor(Qt::SizeHorCursor); - } else if (rectTop.contains(point)) { + } else if (pressedRect.at(2).contains(point)) { widget->setCursor(Qt::SizeVerCursor); - } else if (rectBottom.contains(point)) { + } else if (pressedRect.at(3).contains(point)) { widget->setCursor(Qt::SizeVerCursor); - } else if (rectLeftTop.contains(point)) { + } else if (pressedRect.at(4).contains(point)) { widget->setCursor(Qt::SizeFDiagCursor); - } else if (rectRightTop.contains(point)) { + } else if (pressedRect.at(5).contains(point)) { widget->setCursor(Qt::SizeBDiagCursor); - } else if (rectLeftBottom.contains(point)) { + } else if (pressedRect.at(6).contains(point)) { widget->setCursor(Qt::SizeBDiagCursor); - } else if (rectRightBottom.contains(point)) { + } else if (pressedRect.at(7).contains(point)) { widget->setCursor(Qt::SizeFDiagCursor); } else { widget->setCursor(Qt::ArrowCursor); @@ -77,32 +90,35 @@ bool FramelessWidget::eventFilter(QObject *watched, QEvent *event) } //根据当前鼠标位置,计算XY轴移动了多少 - int offsetX = point.x() - lastPos.x(); - int offsetY = point.y() - lastPos.y(); + int offsetX = point.x() - mousePoint.x(); + int offsetY = point.y() - mousePoint.y(); //根据按下处的位置判断是否是移动控件还是拉伸控件 - if (moveEnable) { - if (pressed) { - widget->move(widget->x() + offsetX, widget->y() + offsetY); - } + if (moveEnable && mousePressed) { + widget->move(widget->x() + offsetX, widget->y() + offsetY); } if (resizeEnable) { - if (pressedLeft) { + int rectX = mouseRect.x(); + int rectY = mouseRect.y(); + int rectW = mouseRect.width(); + int rectH = mouseRect.height(); + + if (pressedArea.at(0)) { int resizeW = widget->width() - offsetX; if (widget->minimumWidth() <= resizeW) { widget->setGeometry(widget->x() + offsetX, rectY, resizeW, rectH); } - } else if (pressedRight) { + } else if (pressedArea.at(1)) { widget->setGeometry(rectX, rectY, rectW + offsetX, rectH); - } else if (pressedTop) { + } else if (pressedArea.at(2)) { int resizeH = widget->height() - offsetY; if (widget->minimumHeight() <= resizeH) { widget->setGeometry(rectX, widget->y() + offsetY, rectW, resizeH); } - } else if (pressedBottom) { + } else if (pressedArea.at(3)) { widget->setGeometry(rectX, rectY, rectW, rectH + offsetY); - } else if (pressedLeftTop) { + } else if (pressedArea.at(4)) { int resizeW = widget->width() - offsetX; int resizeH = widget->height() - offsetY; if (widget->minimumWidth() <= resizeW) { @@ -111,13 +127,13 @@ bool FramelessWidget::eventFilter(QObject *watched, QEvent *event) if (widget->minimumHeight() <= resizeH) { widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH); } - } else if (pressedRightTop) { + } else if (pressedArea.at(5)) { int resizeW = rectW + offsetX; int resizeH = widget->height() - offsetY; if (widget->minimumHeight() <= resizeH) { widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH); } - } else if (pressedLeftBottom) { + } else if (pressedArea.at(6)) { int resizeW = widget->width() - offsetX; int resizeH = rectH + offsetY; if (widget->minimumWidth() <= resizeW) { @@ -126,55 +142,47 @@ bool FramelessWidget::eventFilter(QObject *watched, QEvent *event) if (widget->minimumHeight() <= resizeH) { widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH); } - } else if (pressedRightBottom) { + } else if (pressedArea.at(7)) { int resizeW = rectW + offsetX; int resizeH = rectH + offsetY; widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH); } } } else if (event->type() == QEvent::MouseButtonPress) { - //记住当前控件坐标和宽高以及鼠标按下的坐标 + //记住鼠标按下的坐标+窗体区域 QMouseEvent *mouseEvent = (QMouseEvent *)event; - rectX = widget->x(); - rectY = widget->y(); - rectW = widget->width(); - rectH = widget->height(); - lastPos = mouseEvent->pos(); + mousePoint = mouseEvent->pos(); + mouseRect = widget->geometry(); //判断按下的手柄的区域位置 - if (rectLeft.contains(lastPos)) { - pressedLeft = true; - } else if (rectRight.contains(lastPos)) { - pressedRight = true; - } else if (rectTop.contains(lastPos)) { - pressedTop = true; - } else if (rectBottom.contains(lastPos)) { - pressedBottom = true; - } else if (rectLeftTop.contains(lastPos)) { - pressedLeftTop = true; - } else if (rectRightTop.contains(lastPos)) { - pressedRightTop = true; - } else if (rectLeftBottom.contains(lastPos)) { - pressedLeftBottom = true; - } else if (rectRightBottom.contains(lastPos)) { - pressedRightBottom = true; + if (pressedRect.at(0).contains(mousePoint)) { + pressedArea[0] = true; + } else if (pressedRect.at(1).contains(mousePoint)) { + pressedArea[1] = true; + } else if (pressedRect.at(2).contains(mousePoint)) { + pressedArea[2] = true; + } else if (pressedRect.at(3).contains(mousePoint)) { + pressedArea[3] = true; + } else if (pressedRect.at(4).contains(mousePoint)) { + pressedArea[4] = true; + } else if (pressedRect.at(5).contains(mousePoint)) { + pressedArea[5] = true; + } else if (pressedRect.at(6).contains(mousePoint)) { + pressedArea[6] = true; + } else if (pressedRect.at(7).contains(mousePoint)) { + pressedArea[7] = true; } else { - pressed = true; + mousePressed = true; } } else if (event->type() == QEvent::MouseMove) { //改成用HoverMove识别 } else if (event->type() == QEvent::MouseButtonRelease) { //恢复所有 - pressed = false; - pressedLeft = false; - pressedRight = false; - pressedTop = false; - pressedBottom = false; - pressedLeftTop = false; - pressedRightTop = false; - pressedLeftBottom = false; - pressedRightBottom = false; widget->setCursor(Qt::ArrowCursor); + mousePressed = false; + for (int i = 0; i < 8; ++i) { + pressedArea[i] = false; + } } } @@ -206,5 +214,8 @@ void FramelessWidget::setWidget(QWidget *widget) this->widget->installEventFilter(this); //设置悬停为真,必须设置这个,不然当父窗体里边还有子窗体全部遮挡了识别不到MouseMove,需要识别HoverMove this->widget->setAttribute(Qt::WA_Hover, true); + + isMin = false; + flags = widget->windowFlags(); } } diff --git a/framelesswidget/framelesswidget.h b/framelesswidget/framelesswidget.h index 59fea16..b171fe9 100644 --- a/framelesswidget/framelesswidget.h +++ b/framelesswidget/framelesswidget.h @@ -27,32 +27,28 @@ protected: bool eventFilter(QObject *watched, QEvent *event); private: - int padding; //边距 - bool moveEnable; //可移动 - bool resizeEnable; //可拉伸 - QWidget *widget; //无边框窗体 + //边距+可移动+可拉伸 + int padding; + bool moveEnable; + bool resizeEnable; - bool pressed; //鼠标按下 - bool pressedLeft; //鼠标按下左侧 - bool pressedRight; //鼠标按下右侧 - bool pressedTop; //鼠标按下上侧 - bool pressedBottom; //鼠标按下下侧 - bool pressedLeftTop; //鼠标按下左上侧 - bool pressedRightTop; //鼠标按下右上侧 - bool pressedLeftBottom; //鼠标按下左下侧 - bool pressedRightBottom; //鼠标按下右下侧 + //无边框窗体 + QWidget *widget; - int rectX, rectY, rectW, rectH; //窗体坐标+宽高 - QPoint lastPos; //鼠标按下处坐标 + //鼠标是否按下+按下坐标+按下时窗体区域 + bool mousePressed; + QPoint mousePoint; + QRect mouseRect; - QRect rectLeft; //左侧区域 - QRect rectRight; //右侧区域 - QRect rectTop; //上侧区域 - QRect rectBottom; //下侧区域 - QRect rectLeftTop; //左上侧区域 - QRect rectRightTop; //右上侧区域 - QRect rectLeftBottom; //左下侧区域 - QRect rectRightBottom; //右下侧区域 + //鼠标是否按下某个区域+按下区域的大小 + //依次为 左侧+右侧+上侧+下侧+左上侧+右上侧+左下侧+右下侧 + QList pressedArea; + QList pressedRect; + + //记录是否最小化 + bool isMin; + //存储窗体默认的属性 + Qt::WindowFlags flags; public Q_SLOTS: //设置边距 diff --git a/framelesswidget/framelesswidget2.cpp b/framelesswidget/framelesswidget2.cpp index c58169d..9586618 100644 --- a/framelesswidget/framelesswidget2.cpp +++ b/framelesswidget/framelesswidget2.cpp @@ -1,19 +1,28 @@ #include "framelesswidget2.h" +#include "qdatetime.h" #include "qevent.h" #include "qdebug.h" + #ifdef Q_OS_WIN #include "windows.h" +#pragma comment (lib,"user32.lib") #endif +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + FramelessWidget2::FramelessWidget2(QWidget *parent) : QWidget(parent) { - padding = 5; + padding = 8; + moveEnable = true; + resizeEnable = true; + + //安装事件过滤器识别拖动 this->installEventFilter(this); } bool FramelessWidget2::eventFilter(QObject *watched, QEvent *event) { - if (watched == this) { + if (watched == this && moveEnable) { static QPoint mousePoint; static bool mousePressed = false; @@ -36,50 +45,91 @@ bool FramelessWidget2::eventFilter(QObject *watched, QEvent *event) return QWidget::eventFilter(watched, event); } +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) +bool FramelessWidget2::nativeEvent(const QByteArray &eventType, void *message, qintptr *result) +#else bool FramelessWidget2::nativeEvent(const QByteArray &eventType, void *message, long *result) +#endif { + if (eventType == "windows_generic_MSG") { #ifdef Q_OS_WIN - MSG *msg = (MSG *)message; - switch (msg->message) { - case WM_NCHITTEST: { - QPoint pos = mapFromGlobal(QPoint(LOWORD(msg->lParam), HIWORD(msg->lParam))); + MSG *msg = static_cast(message); + //qDebug() << TIMEMS << "nativeEvent" << msg->wParam << msg->message; + + //不同的消息类型和参数进行不同的处理 + if (msg->message == WM_NCCALCSIZE) { + *result = 0; + return true; + } else if (msg->message == WM_NCHITTEST) { + //计算鼠标对应的屏幕坐标 + long x = LOWORD(msg->lParam); + long y = HIWORD(msg->lParam); + QPoint pos = mapFromGlobal(QPoint(x, y)); + + //判断当前鼠标位置在哪个区域 bool left = pos.x() < padding; bool right = pos.x() > width() - padding; bool top = pos.y() < padding; bool bottom = pos.y() > height() - padding; - if (left && top) { - *result = HTTOPLEFT; - } else if (left && bottom) { - *result = HTBOTTOMLEFT; - } else if (right && top) { - *result = HTTOPRIGHT; - } else if (right && bottom) { - *result = HTBOTTOMRIGHT; - } else if (left) { - *result = HTLEFT; - } else if (right) { - *result = HTRIGHT; - } else if (top) { - *result = HTTOP; - } else if (bottom) { - *result = HTBOTTOM; - } else { - return false; - } - return true; - } - break; - default: - break; - } -#endif + //鼠标移动到四个角,这个消息是当鼠标移动或者有鼠标键按下时候发出的 + *result = 0; + if (resizeEnable) { + if (left && top) { + *result = HTTOPLEFT; + } else if (left && bottom) { + *result = HTBOTTOMLEFT; + } else if (right && top) { + *result = HTTOPRIGHT; + } else if (right && bottom) { + *result = HTBOTTOMRIGHT; + } else if (left) { + *result = HTLEFT; + } else if (right) { + *result = HTRIGHT; + } else if (top) { + *result = HTTOP; + } else if (bottom) { + *result = HTBOTTOM; + } + } + + //先处理掉拉伸 + if (0 != *result) { + return true; + } + } +#endif + } else if (eventType == "NSEvent") { +#ifdef Q_OS_MACOS +#endif + } else if (eventType == "xcb_generic_event_t") { +#ifdef Q_OS_LINUX +#endif + } return false; } +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) #ifdef Q_OS_WIN bool FramelessWidget2::winEvent(MSG *message, long *result) { return nativeEvent("windows_generic_MSG", message, result); } #endif +#endif + +void FramelessWidget2::setPadding(int padding) +{ + this->padding = padding; +} + +void FramelessWidget2::setMoveEnable(bool moveEnable) +{ + this->moveEnable = moveEnable; +} + +void FramelessWidget2::setResizeEnable(bool resizeEnable) +{ + this->resizeEnable = resizeEnable; +} diff --git a/framelesswidget/framelesswidget2.h b/framelesswidget/framelesswidget2.h index e31e5cd..0bca12c 100644 --- a/framelesswidget/framelesswidget2.h +++ b/framelesswidget/framelesswidget2.h @@ -16,13 +16,32 @@ public: protected: bool eventFilter(QObject *watched, QEvent *event); + + //拦截系统事件用于修复系统休眠后唤醒程序的BUG +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + bool nativeEvent(const QByteArray &eventType, void *message, qintptr *result); +#else bool nativeEvent(const QByteArray &eventType, void *message, long *result); +#endif + + //Qt4的写法 +#if (QT_VERSION < QT_VERSION_CHECK(5,0,0)) #ifdef Q_OS_WIN bool winEvent(MSG *message, long *result); #endif +#endif private: + //边距+可移动+可拉伸 int padding; + bool moveEnable; + bool resizeEnable; + +public: + //设置边距+可拖动+可拉伸 + void setPadding(int padding); + void setMoveEnable(bool moveEnable); + void setResizeEnable(bool resizeEnable); }; #endif // FRAMELESSWIDGET2_H diff --git a/framelesswidget/frmframelesswidget.cpp b/framelesswidget/frmframelesswidget.cpp index e8b2f57..279121f 100644 --- a/framelesswidget/frmframelesswidget.cpp +++ b/framelesswidget/frmframelesswidget.cpp @@ -11,8 +11,8 @@ frmFramelessWidget::frmFramelessWidget(QWidget *parent) : QWidget(parent), ui(ne { ui->setupUi(this); widget1 = 0; - widget2 = 0; frameless = 0; + frameless2 = 0; } frmFramelessWidget::~frmFramelessWidget() @@ -74,6 +74,9 @@ void frmFramelessWidget::stateChanged1(int arg1) if (frameless != 0) { frameless->setMoveEnable(arg1 != 0); } + if (frameless2 != 0) { + frameless2->setMoveEnable(arg1 != 0); + } } void frmFramelessWidget::stateChanged2(int arg1) @@ -81,14 +84,17 @@ void frmFramelessWidget::stateChanged2(int arg1) if (frameless != 0) { frameless->setResizeEnable(arg1 != 0); } + if (frameless2 != 0) { + frameless2->setResizeEnable(arg1 != 0); + } } void frmFramelessWidget::on_pushButton_2_clicked() { - if (widget2 == 0) { - widget2 = new FramelessWidget2; - this->initWidget(widget2); + if (frameless2 == 0) { + frameless2 = new FramelessWidget2; + this->initWidget(frameless2); } - widget2->show(); + frameless2->show(); } diff --git a/framelesswidget/frmframelesswidget.h b/framelesswidget/frmframelesswidget.h index 6d7d648..52dc15c 100644 --- a/framelesswidget/frmframelesswidget.h +++ b/framelesswidget/frmframelesswidget.h @@ -23,8 +23,8 @@ protected: private: Ui::frmFramelessWidget *ui; QWidget *widget1; - FramelessWidget2 *widget2; FramelessWidget *frameless; + FramelessWidget2 *frameless2; private slots: void initWidget(QWidget *w); diff --git a/framelesswidget/main.cpp b/framelesswidget/main.cpp index a51e854..4c839b4 100644 --- a/framelesswidget/main.cpp +++ b/framelesswidget/main.cpp @@ -6,6 +6,9 @@ int main(int argc, char *argv[]) { +#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0)) + QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor); +#endif QApplication a(argc, argv); a.setFont(QFont("Microsoft Yahei", 9));