From 1a936f389aff2e5289fcd5481c4bbb715feaaef6 Mon Sep 17 00:00:00 2001 From: tianduanrui <2407223896@qq.com> Date: Sat, 21 Oct 2017 21:55:12 +0800 Subject: [PATCH] add framelesshelper --- a0-qqtfoundation.pro | 3 +- examples/exquisite/qqtexquisiteform.ui | 64 ++-- .../framelesshelperwidget.pro | 88 +++++ examples/framelesshelperwidget/main.cpp | 11 + examples/framelesshelperwidget/widget.cpp | 23 ++ examples/framelesshelperwidget/widget.h | 22 ++ examples/framelesshelperwidget/widget.ui | 92 +++++ src/exquisite/qqtframelesshelper.cpp | 95 +++++ src/exquisite/qqtframelesshelper.h | 37 ++ src/exquisite/qqtframelesshelperprivate.cpp | 337 ++++++++++++++++++ src/exquisite/qqtframelesshelperprivate.h | 75 ++++ src/qqt_source.pri | 8 +- 12 files changed, 819 insertions(+), 36 deletions(-) create mode 100644 examples/framelesshelperwidget/framelesshelperwidget.pro create mode 100644 examples/framelesshelperwidget/main.cpp create mode 100644 examples/framelesshelperwidget/widget.cpp create mode 100644 examples/framelesshelperwidget/widget.h create mode 100644 examples/framelesshelperwidget/widget.ui create mode 100644 src/exquisite/qqtframelesshelper.cpp create mode 100644 src/exquisite/qqtframelesshelper.h create mode 100644 src/exquisite/qqtframelesshelperprivate.cpp create mode 100644 src/exquisite/qqtframelesshelperprivate.h diff --git a/a0-qqtfoundation.pro b/a0-qqtfoundation.pro index 131fdc3f..a6efef1f 100644 --- a/a0-qqtfoundation.pro +++ b/a0-qqtfoundation.pro @@ -1,7 +1,8 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS += src/qqt.pro +SUBDIRS += src/qqt.pro \ + examples/framelesshelperwidget #SUBDIRS += examples/qqtframe SUBDIRS += examples/qqtframe2 #SUBDIRS += examples/animationframe diff --git a/examples/exquisite/qqtexquisiteform.ui b/examples/exquisite/qqtexquisiteform.ui index c4a027c5..e20ab123 100644 --- a/examples/exquisite/qqtexquisiteform.ui +++ b/examples/exquisite/qqtexquisiteform.ui @@ -13,39 +13,37 @@ QQtExquisiteForm - - - - 40 - 30 - 241 - 251 - - - - - - - 300 - 30 - 251 - 251 - - - - - - - 40 - 380 - 501 - 22 - - - - Qt::Horizontal - - + + + + + + Tab 1 + + + + + + + + + + + + + Tab 2 + + + + + + + + Qt::Horizontal + + + + diff --git a/examples/framelesshelperwidget/framelesshelperwidget.pro b/examples/framelesshelperwidget/framelesshelperwidget.pro new file mode 100644 index 00000000..e7cc2918 --- /dev/null +++ b/examples/framelesshelperwidget/framelesshelperwidget.pro @@ -0,0 +1,88 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2017-10-21T21:26:55 +# +#------------------------------------------------- +#include QQt's header (add QQt header to includepath) +include(../../src/qqt_header.pri) + +#CONFIG += BUILD_SRC +contains (CONFIG, BUILD_SRC) { + #if you want to build src but not link QQt in this project + #include(../../src/qqt.pri) +} else { + #if you want to link QQt library + message(Link QQt to $${TARGET} $${QKIT_} from $${SYSNAME} $${BUILD} on $${QMAKE_HOST.os}) + equals(QMAKE_HOST.os, Darwin) { + equals(QKIT_, macOS) { + LIBS += -F/Users/abel/Develop/c0-buildstation/a0-qqtfoundation/$${SYSNAME}/$${BUILD}/src/bin + LIBS += -framework QQt + } else: equals(QKIT_, Android) { + LIBS += -L/Users/abel/Develop/c0-buildstation/a0-qqtfoundation/$${SYSNAME}/$${BUILD}/src/bin + LIBS += -lQQt + } else: equals(QKIT_, ANDROIDX86) { + LIBS += -L/Users/abel/Develop/c0-buildstation/a0-qqtfoundation/$${SYSNAME}/$${BUILD}/src/bin + LIBS += -lQQt + } + } else: equals(QMAKE_HOST.os, Linux) { + LIBS += -L/home/abel/Develop/c0-buildstation/a0-qqtfoundation/$${SYSNAME}/$${BUILD}/src/bin + LIBS += -lQQt + } else: equals(QMAKE_HOST.os, Windows) { + LIBS += -LC:/Users/Administrator/Develop/c0-build/a0-qqtfoundation/$${SYSNAME}/$${BUILD}/src/bin + LIBS += -lQQt + } +} +############ +##install +############ +#CONFIG += can_install +can_install:equals(QKIT_, MIPS32) { + target.path = /Application + INSTALLS += target +} else: unix { + equals(QKIT_, macOS) { + target.path = /Applications + INSTALLS += target + } +} + +equals(QKIT_, macOS) { + CONFIG += app_bundle +} +equals(QKIT_, Android) { + CONFIG += mobility + MOBILITY = + #DISTFILES += \ + # android/AndroidManifest.xml + + #ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android +} + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = framelesshelperwidget +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +SOURCES += \ + main.cpp \ + widget.cpp + +HEADERS += \ + widget.h + +FORMS += \ + widget.ui diff --git a/examples/framelesshelperwidget/main.cpp b/examples/framelesshelperwidget/main.cpp new file mode 100644 index 00000000..90b6d53f --- /dev/null +++ b/examples/framelesshelperwidget/main.cpp @@ -0,0 +1,11 @@ +#include "widget.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Widget w; + w.show(); + + return a.exec(); +} diff --git a/examples/framelesshelperwidget/widget.cpp b/examples/framelesshelperwidget/widget.cpp new file mode 100644 index 00000000..4d7bbcec --- /dev/null +++ b/examples/framelesshelperwidget/widget.cpp @@ -0,0 +1,23 @@ +#include "widget.h" +#include "ui_widget.h" + +#include "qqtframelesshelper.h" + +Widget::Widget(QWidget* parent) : + QWidget(parent), + ui(new Ui::Widget) +{ + ui->setupUi(this); + + QQtFramelessHelper* frameless = new QQtFramelessHelper(this); + frameless->addDragWidget(this); + frameless->setCloseButton(ui->pushButtonClose); + frameless->setMaximizedButton(ui->pushButtonMax); + frameless->setRestoreButton(ui->pushButtonRestore); + frameless->setMinimizedButton(ui->pushButtonMin, false); +} + +Widget::~Widget() +{ + delete ui; +} diff --git a/examples/framelesshelperwidget/widget.h b/examples/framelesshelperwidget/widget.h new file mode 100644 index 00000000..896177c1 --- /dev/null +++ b/examples/framelesshelperwidget/widget.h @@ -0,0 +1,22 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include + +namespace Ui { +class Widget; +} + +class Widget : public QWidget +{ + Q_OBJECT + +public: + explicit Widget(QWidget *parent = 0); + ~Widget(); + +private: + Ui::Widget *ui; +}; + +#endif // WIDGET_H diff --git a/examples/framelesshelperwidget/widget.ui b/examples/framelesshelperwidget/widget.ui new file mode 100644 index 00000000..44123bfc --- /dev/null +++ b/examples/framelesshelperwidget/widget.ui @@ -0,0 +1,92 @@ + + + Widget + + + + 0 + 0 + 400 + 300 + + + + Widget + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 最小化 + + + + + + + 最大化 + + + + + + + 还原 + + + + + + + 关闭 + + + + + + + + + Qt::Vertical + + + + 20 + 266 + + + + + + + + + + diff --git a/src/exquisite/qqtframelesshelper.cpp b/src/exquisite/qqtframelesshelper.cpp new file mode 100644 index 00000000..4d308532 --- /dev/null +++ b/src/exquisite/qqtframelesshelper.cpp @@ -0,0 +1,95 @@ +//#include "stdafx.h" + +#include "qqtframelesshelper.h" +#include "qqtframelesshelperprivate.h" + +#include +#include +#include + +QQtFramelessHelper::QQtFramelessHelper(QWidget* parent) : QObject(parent) +{ + d = new QQtFramelessHelperPrivate(parent); +} + +void QQtFramelessHelper::setResizeMargins(int margin) +{ + setResizeMargins(QMargins(margin, margin, margin, margin)); +} + +void QQtFramelessHelper::setResizeMargins(const QMargins& margins) +{ + d->margins = margins; +} + +void QQtFramelessHelper::setCloseButton(QPushButton* button, bool edgeResize) +{ + d->buttonClose = button; + connect(d->buttonClose, SIGNAL(clicked(bool)), + d->parent, SLOT(close())); + + if (edgeResize) + { + d->addEdgeWidget(button); + } +} + +void QQtFramelessHelper::setMaximizedButton(QPushButton* button, bool edgeResize) +{ + d->buttonMaximized = button; + connect(d->buttonMaximized, SIGNAL(clicked(bool)), + d->parent, SLOT(showMaximized())); + + if (edgeResize) + { + d->addEdgeWidget(button); + } + + d->refreshMaximizedButton(); +} + +void QQtFramelessHelper::setMinimizedButton(QPushButton* button, bool edgeResize) +{ + d->buttonMinimized = button; + connect(d->buttonMinimized, SIGNAL(clicked(bool)), + d->parent, SLOT(showMinimized())); + + if (edgeResize) + { + d->addEdgeWidget(button); + } +} + +void QQtFramelessHelper::setRestoreButton(QPushButton* button, bool edgeResize) +{ + d->buttonRestore = button; + connect(d->buttonRestore, SIGNAL(clicked(bool)), + d->parent, SLOT(showNormal())); + + if (edgeResize) + { + d->addEdgeWidget(button); + } + + d->refreshMaximizedButton(); +} + +void QQtFramelessHelper::addEdgeWidget(QWidget* widget) +{ + d->addEdgeWidget(widget); +} + +void QQtFramelessHelper::addDragWidget(QWidget* widget) +{ + d->addDragWidget(widget); +} + + + + + + + + + + diff --git a/src/exquisite/qqtframelesshelper.h b/src/exquisite/qqtframelesshelper.h new file mode 100644 index 00000000..8210dee4 --- /dev/null +++ b/src/exquisite/qqtframelesshelper.h @@ -0,0 +1,37 @@ +#ifndef QQTFRAMELESSHELPER_H +#define QQTFRAMELESSHELPER_H + +/** + * T.D.R (QQ:2657635903) mod 2017年10月21日21:24:43 +**/ + +#include +#include + + +class QPushButton; +class QWidget; +class QQtFramelessHelperPrivate; + +class QQtFramelessHelper : public QObject +{ + Q_OBJECT +public: + explicit QQtFramelessHelper(QWidget* parent); + + void setResizeMargins(int margin); + void setResizeMargins(const QMargins& margins); + + void setCloseButton(QPushButton* button, bool edgeResize = true); + void setMaximizedButton(QPushButton* button, bool edgeResize = true); + void setMinimizedButton(QPushButton* button, bool edgeResize = true); + void setRestoreButton(QPushButton* button, bool edgeResize = true); + + void addEdgeWidget(QWidget* widget); + void addDragWidget(QWidget* widget); + +private: + QQtFramelessHelperPrivate* d; +}; + +#endif // QQTFRAMELESSHELPER_H diff --git a/src/exquisite/qqtframelesshelperprivate.cpp b/src/exquisite/qqtframelesshelperprivate.cpp new file mode 100644 index 00000000..55083dd6 --- /dev/null +++ b/src/exquisite/qqtframelesshelperprivate.cpp @@ -0,0 +1,337 @@ +#include "qqtframelesshelperprivate.h" +#include +#include +#include +#include +#include +#include + +QQtFramelessHelperPrivate::QQtFramelessHelperPrivate(QWidget* parent) + : parent(parent), + isMaximized(false), + direction(None), + buttonMaximized(0), + buttonRestore(0), + buttonClose(0), + buttonMinimized(0), + isMousePressed(false), + QObject(parent) +{ + margins = QMargins(5, 5, 5, 5); + parent->setWindowFlags(parent->windowFlags() | (Qt::FramelessWindowHint)); + parent->installEventFilter(this); + + + timer = new QTimer(this); + timer->setInterval(400); + connect(timer, SIGNAL(timeout()), this, SLOT(checkPos())); + + timer->start(); +} + +void QQtFramelessHelperPrivate::addEdgeWidget(QWidget* widget) +{ + if (!edgeWidgets.contains(widget)) + { + edgeWidgets.append(widget); + + if (!dragWidgets.contains(widget)) + { + widget->installEventFilter(this); + } + } +} + +void QQtFramelessHelperPrivate::addDragWidget(QWidget* widget) +{ + if (!dragWidgets.contains(widget)) + { + dragWidgets.append(widget); + + if (!edgeWidgets.contains(widget)) + { + widget->installEventFilter(this); + } + } +} + +void QQtFramelessHelperPrivate::checkPos() +{ + QRect rectMustIn = parent->frameGeometry(); + QRect rectMustNotIn = rectMustIn.marginsRemoved(margins); + + QPoint cursorPos = QCursor::pos(); + + if (isMaximized || + !parent->isActiveWindow() || + !rectMustIn.contains(cursorPos) || + rectMustNotIn.contains(cursorPos)) + { + direction = None; + parent->unsetCursor(); + return; + } + + int baseLeftCoord, baseTopCoord, baseRightCoord, baseBottomCoord; + + rectMustNotIn.getCoords(&baseLeftCoord, &baseTopCoord, &baseRightCoord, &baseBottomCoord); + + int x, y; + x = cursorPos.x(); + y = cursorPos.y(); + + direction = None; + + if (x < baseLeftCoord) + { + if (y < baseTopCoord) + { + direction = LeftTop; + } + else if (y > baseBottomCoord) + { + direction = LeftBottom; + } + else + { + direction = Left; + } + } + else if (x > baseRightCoord) + { + if (y < baseTopCoord) + { + direction = RightTop; + } + else if (y > baseBottomCoord) + { + direction = RightBottom; + } + else + { + direction = Right; + } + } + + if (direction == None) + { + if (y < baseTopCoord) + { + direction = Top; + } + else + { + direction = Bottom; + } + } + + switch (direction) + { + case Left: + case Right: + parent->setCursor(Qt::SizeHorCursor); + break; + + case Top: + case Bottom: + parent->setCursor(Qt::SizeVerCursor); + break; + + case LeftTop: + case RightBottom: + parent->setCursor(Qt::SizeFDiagCursor); + break; + + case LeftBottom: + case RightTop: + parent->setCursor(Qt::SizeBDiagCursor); + break; + } +} + +void QQtFramelessHelperPrivate::resize(const QPoint& cursorPos) +{ + QSize oldSize = parent->size(); + + int x, y, width = 0, height = 0; + + switch (direction) + { + case Left: // left + width = oldSize.width() - cursorPos.x(); + height = oldSize.height(); + + x = parent->pos().x() - (width - oldSize.width()); + y = parent->pos().y(); + break; + + case Right: //right + width = cursorPos.x(); + height = oldSize.height(); + + x = parent->pos().x(); + y = parent->pos().y(); + break; + + case LeftTop: //left top + width = oldSize.width() - cursorPos.x(); + height = oldSize.height() - cursorPos.y(); + + x = parent->pos().x() - (width - oldSize.width()); + y = parent->pos().y() - (height - oldSize.height()); + break; + + case RightTop: //right top + width = cursorPos.x(); + height = oldSize.height() - cursorPos.y(); + + x = parent->pos().x(); + y = parent->pos().y() - (height - oldSize.height()); + + break; + + case LeftBottom: //left bottom + width = oldSize.width() - cursorPos.x(); + height = cursorPos.y(); + + x = parent->pos().x() - (width - oldSize.width()); + y = parent->pos().y(); + + break; + + case RightBottom: //right bottom + width = cursorPos.x(); + height = cursorPos.y(); + + x = parent->pos().x(); + y = parent->pos().y(); + break; + + case Top: //top + width = oldSize.width(); + height = oldSize.height() - cursorPos.y(); + + x = parent->pos().x(); + y = parent->pos().y() - (height - oldSize.height()); + break; + + case Bottom: //bottom + width = oldSize.width(); + height = cursorPos.y(); + + x = parent->pos().x(); + y = parent->pos().y(); + break; + } + + if (width > (margins.left() + margins.right()) && + height > (margins.top() + margins.bottom())) + { + parent->move(x, y); + parent->resize(width, height); + } +} + +void QQtFramelessHelperPrivate::refreshMaximizedButton() +{ + isMaximized = parent->windowState().testFlag(Qt::WindowMaximized); + + if (buttonRestore != 0) + { + buttonRestore->setVisible(isMaximized); + } + + if (buttonMaximized != 0) + { + buttonMaximized->setVisible(!isMaximized); + } +} + +bool QQtFramelessHelperPrivate::eventFilter(QObject* obj, QEvent* event) +{ + do + { + if (event->type() == QEvent::WindowStateChange) + { + refreshMaximizedButton(); + break; + } + + if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent* e = (QMouseEvent*)event; + + // no move, no drag + if (e->button() != Qt::LeftButton || isMaximized) + { + break; + } + + checkPos(); + + if ((obj == parent || edgeWidgets.contains(qobject_cast(obj))) && direction != None) + { + isMousePressed = true; + operation = MoveResize; + timer->stop(); + return true; + } + + if (dragWidgets.contains(qobject_cast(obj)) && direction == None) + { + isMousePressed = true; + operation = MoveDrag; + dragBasePoint = e->globalPos() - parent->pos(); + timer->stop(); + return true; + } + + break; + } + + if (event->type() == QEvent::MouseMove && isMousePressed) + { + QMouseEvent* e = (QMouseEvent*)event; + + if (operation == MoveDrag) + { + parent->move(e->globalPos() - dragBasePoint); + return true; + } + + if (operation == MoveResize) + { + if (obj != parent) + { + QWidget* w = qobject_cast(obj); + resize(w->mapTo(parent, e->pos())); + } + else + { + resize(e->pos()); + } + return true; + } + break; + } + + if (event->type() == QEvent::MouseButtonRelease) + { + QMouseEvent* e = (QMouseEvent*)event; + if (e->button() == Qt::LeftButton && isMousePressed) + { + isMousePressed = false; + operation = MoveNone; + timer->start(); + return true; + } + break; + } + + } + while (false); + + + + return QObject::eventFilter(obj, event); +} diff --git a/src/exquisite/qqtframelesshelperprivate.h b/src/exquisite/qqtframelesshelperprivate.h new file mode 100644 index 00000000..7d028385 --- /dev/null +++ b/src/exquisite/qqtframelesshelperprivate.h @@ -0,0 +1,75 @@ +#ifndef QQTFRAMELESSHELPERPRIVATE_H +#define QQTFRAMELESSHELPERPRIVATE_H + +#include +#include +#include + +class QPushButton; +class QWidget; +class QEvent; +class QTimer; +class QMouseEvent; +class QQtFramelessHelperPrivate : public QObject +{ + Q_OBJECT +public: + QPushButton* buttonMaximized; + QPushButton* buttonRestore; + QPushButton* buttonClose; + QPushButton* buttonMinimized; + + QList dragWidgets; + QList edgeWidgets; + + QWidget* parent; + QMargins margins; + + QQtFramelessHelperPrivate(QWidget* parent); + void addEdgeWidget(QWidget* widget); + void addDragWidget(QWidget* widget); + + void refreshMaximizedButton(); + +protected: + enum MoveDirection + { + None = 0, + Left, + Right, + LeftTop, + RightTop, + LeftBottom, + RightBottom, + Top, + Bottom, + }; + + enum MoveOperation + { + MoveNone = 0, + MoveResize, + MoveDrag, + }; + +protected: + bool eventFilter(QObject* obj, QEvent* event); + +private slots: + void checkPos(); + + void resize(const QPoint& cursorPos); + +private: + bool isMaximized; + MoveDirection direction; + MoveOperation operation; + + bool isMousePressed; + + QTimer* timer; + + QPoint dragBasePoint; +}; + +#endif // QQTFRAMELESSHELPERPRIVATE_H diff --git a/src/qqt_source.pri b/src/qqt_source.pri index 546d5df0..7a5e943b 100644 --- a/src/qqt_source.pri +++ b/src/qqt_source.pri @@ -28,12 +28,16 @@ SOURCES = \ $$PWD/exquisite/qqtcustomprogressbar.cpp \ $$PWD/exquisite/qqtcustomspeedmeter.cpp \ $$PWD/exquisite/qqtcustomsliderruler.cpp \ - $$PWD/exquisite/qqtcustompiano.cpp + $$PWD/exquisite/qqtcustompiano.cpp \ + $$PWD/exquisite/qqtframelesshelper.cpp \ + $$PWD/exquisite/qqtframelesshelperprivate.cpp HEADERS = \ $$PWD/exquisite/qqtcustomprogressbar.h \ $$PWD/exquisite/qqtcustomspeedmeter.h \ $$PWD/exquisite/qqtcustomsliderruler.h \ - $$PWD/exquisite/qqtcustompiano.h + $$PWD/exquisite/qqtcustompiano.h \ + $$PWD/exquisite/qqtframelesshelper.h \ + $$PWD/exquisite/qqtframelesshelperprivate.h #root dir win32 {