I. Preface
In a previous article, I wrote about a generic mobile control, which is used to pass in any widget control and move freely in the parent container. This article is about a general borderless class, which does not exactly mean that the control should be called a component. The control is something to see and has drawing requirements, which need to be attached to the control. In the projects we usually do, in order to make the U interface beautiful, many people will use the custom borderless form to deal with, beautify the title bar and so on. They will face the same problem. After setting the custom borderless form, they will handle the movement and stretching of the form themselves. If there are many borderless forms, many people will think of writing duplicate code everywhere. To achieve mobility or stretching, why not encapsulate a class to accomplish this function, just pass it directly into the form. In QDialog form, you can stretch the lower right corner by setting an attribute sizeGripEnabled, which is not enough to meet all the requirements. In many cases, we need to stretch around the four corners and upper and lower corners. This requires rewriting, installing event filters, recognizing that the mouse moves to a certain area, the shape of the mouse changes automatically, and then identifying whether it has been changed or not. After press, press the words to do the corresponding processing, the corresponding processing core is to reset the XY axis coordinates and size of the form.
Open source address: https://gitee.com/feiyangqingyun/QWidgetDemo https://github.com/feiyangqingyun/QWidgetDemo
II. Functions of Realization
- 1: You can specify a widget that requires no borders
- 2: All eight directions around the frame can be stretched freely.
- 3: The margin of the corresponding position can be set to identify larger areas.
- 4: Can be set to allow dragging
- 5: Can be set to allow stretching
III. EFFECT CHARACTERISTICS
Header file code
#ifndef FRAMELESSWIDGET_H #define FRAMELESSWIDGET_H /** * Borderless Form Class Author: feiyangqingyun(QQ:517216493) 2019-10-03 * 1:You can specify a widget that requires no borders * 2:All eight directions around the frame can be stretched freely. * 3:The margin of the corresponding position can be set to identify larger areas. * 4:Can be set to allow dragging * 5:Can be set to allow stretching */ #include <QWidget> #ifdef quc #if (QT_VERSION < QT_VERSION_CHECK(5,7,0)) #include <QtDesigner/QDesignerExportWidget> #else #include <QtUiPlugin/QDesignerExportWidget> #endif class QDESIGNER_WIDGET_EXPORT FramelessWidget : public QObject #else class FramelessWidget : public QObject #endif { Q_OBJECT public: explicit FramelessWidget(QObject *parent = 0); protected: bool eventFilter(QObject *watched, QEvent *event); private: int padding; //Margin bool moveEnable; //portability bool resizeEnable; //Stretchable QWidget *widget; //Borderless Form bool pressed; //Mouse down bool pressedLeft; //Press the left mouse bool pressedRight; //Press the mouse to the right bool pressedTop; //Press the mouse down the upper side bool pressedBottom; //Press the mouse down the lower side bool pressedLeftTop; //Press the mouse on the upper left side bool pressedRightTop; //Press the mouse on the upper right side bool pressedLeftBottom; //Press the mouse on the lower left side bool pressedRightBottom; //Lower right mouse down int rectX, rectY, rectW, rectH; //Form coordinates + width and height QPoint lastPos; //Click the coordinates below QRect rectLeft; //Left area QRect rectRight; //Right region QRect rectTop; //Upper side area QRect rectBottom; //Underside area QRect rectLeftTop; //Left upper region QRect rectRightTop; //Upper right area QRect rectLeftBottom; //Left lower region QRect rectRightBottom; //Right lower region public Q_SLOTS: //Setting margins void setPadding(int padding); //Set drag + stretch void setMoveEnable(bool moveEnable); void setResizeEnable(bool resizeEnable); //Set the form to be borderless void setWidget(QWidget *widget); }; #endif // FRAMELESSWIDGET_H
V. Core Code
#include "framelesswidget.h" #include "qevent.h" #include "qdebug.h" FramelessWidget::FramelessWidget(QObject *parent) : QObject(parent) { padding = 8; moveEnable = true; resizeEnable = true; widget = 0; pressed = false; pressedLeft = false; pressedRight = false; pressedTop = false; pressedBottom = false; pressedLeftTop = false; pressedRightTop = false; pressedLeftBottom = false; pressedRightBottom = false; //If the parent class is a form, set it directly if (parent->isWidgetType()) { setWidget((QWidget *)parent); } } bool FramelessWidget::eventFilter(QObject *watched, QEvent *event) { if (widget != 0 && watched == widget) { if (event->type() == QEvent::Resize) { //To recalculate the area of eight tracing points, the function of the tracing point area is to calculate whether the mouse coordinates are in a certain area or not. int width = widget->width(); int height = widget->height(); //Left tracing area rectLeft = QRect(0, padding, padding, height - padding * 2); //Topside tracing area rectTop = QRect(padding, 0, width - padding * 2, padding); //Right tracing area rectRight = QRect(width - padding, padding, padding, height - padding * 2); //Lower outline area rectBottom = QRect(padding, height - padding, width - padding * 2, padding); //Top left corner tracing area rectLeftTop = QRect(0, 0, padding, padding); //Top right corner tracing area rectRightTop = QRect(width - padding, 0, padding, padding); //The lower left corner tracing area rectLeftBottom = QRect(0, height - padding, padding, padding); //The lower right corner tracing area rectRightBottom = QRect(width - padding, height - padding, padding, padding); } else if (event->type() == QEvent::HoverMove) { //Set the corresponding mouse shape, which must be placed here rather than below, because it can be recognized when the mouse is not pressed. QHoverEvent *hoverEvent = (QHoverEvent *)event; QPoint point = hoverEvent->pos(); if (resizeEnable) { if (rectLeft.contains(point)) { widget->setCursor(Qt::SizeHorCursor); } else if (rectRight.contains(point)) { widget->setCursor(Qt::SizeHorCursor); } else if (rectTop.contains(point)) { widget->setCursor(Qt::SizeVerCursor); } else if (rectBottom.contains(point)) { widget->setCursor(Qt::SizeVerCursor); } else if (rectLeftTop.contains(point)) { widget->setCursor(Qt::SizeFDiagCursor); } else if (rectRightTop.contains(point)) { widget->setCursor(Qt::SizeBDiagCursor); } else if (rectLeftBottom.contains(point)) { widget->setCursor(Qt::SizeBDiagCursor); } else if (rectRightBottom.contains(point)) { widget->setCursor(Qt::SizeFDiagCursor); } else { widget->setCursor(Qt::ArrowCursor); } } //Calculate how much the XY axis has moved based on the current mouse position int offsetX = point.x() - lastPos.x(); int offsetY = point.y() - lastPos.y(); //Determine whether a mobile control or a stretch control is based on the position at which it is pressed if (moveEnable) { if (pressed) { widget->move(widget->x() + offsetX, widget->y() + offsetY); } } if (resizeEnable) { if (pressedLeft) { int resizeW = widget->width() - offsetX; if (widget->minimumWidth() <= resizeW) { widget->setGeometry(widget->x() + offsetX, rectY, resizeW, rectH); } } else if (pressedRight) { widget->setGeometry(rectX, rectY, rectW + offsetX, rectH); } else if (pressedTop) { int resizeH = widget->height() - offsetY; if (widget->minimumHeight() <= resizeH) { widget->setGeometry(rectX, widget->y() + offsetY, rectW, resizeH); } } else if (pressedBottom) { widget->setGeometry(rectX, rectY, rectW, rectH + offsetY); } else if (pressedLeftTop) { int resizeW = widget->width() - offsetX; int resizeH = widget->height() - offsetY; if (widget->minimumWidth() <= resizeW) { widget->setGeometry(widget->x() + offsetX, widget->y(), resizeW, resizeH); } if (widget->minimumHeight() <= resizeH) { widget->setGeometry(widget->x(), widget->y() + offsetY, resizeW, resizeH); } } else if (pressedRightTop) { 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) { int resizeW = widget->width() - offsetX; int resizeH = rectH + offsetY; if (widget->minimumWidth() <= resizeW) { widget->setGeometry(widget->x() + offsetX, widget->y(), resizeW, resizeH); } if (widget->minimumHeight() <= resizeH) { widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH); } } else if (pressedRightBottom) { int resizeW = rectW + offsetX; int resizeH = rectH + offsetY; widget->setGeometry(widget->x(), widget->y(), resizeW, resizeH); } } } else if (event->type() == QEvent::MouseButtonPress) { //Keep in mind the coordinates and width of the current control and the coordinates pressed by the mouse QMouseEvent *mouseEvent = (QMouseEvent *)event; rectX = widget->x(); rectY = widget->y(); rectW = widget->width(); rectH = widget->height(); lastPos = mouseEvent->pos(); //Judge the area position of the pressed handle 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; } else { pressed = true; } } else if (event->type() == QEvent::MouseMove) { //Change to HoverMove Recognition } else if (event->type() == QEvent::MouseButtonRelease) { //Restore all pressed = false; pressedLeft = false; pressedRight = false; pressedTop = false; pressedBottom = false; pressedLeftTop = false; pressedRightTop = false; pressedLeftBottom = false; pressedRightBottom = false; widget->setCursor(Qt::ArrowCursor); } } return QObject::eventFilter(watched, event); } void FramelessWidget::setPadding(int padding) { this->padding = padding; } void FramelessWidget::setMoveEnable(bool moveEnable) { this->moveEnable = moveEnable; } void FramelessWidget::setResizeEnable(bool resizeEnable) { this->resizeEnable = resizeEnable; } void FramelessWidget::setWidget(QWidget *widget) { if (this->widget == 0) { this->widget = widget; //Set Mouse Tracking to True this->widget->setMouseTracking(true); //Binding Event Filter this->widget->installEventFilter(this); //To set hover to true, you must set this, otherwise when the parent form and the child form are all blocked from recognizing MouseMove, you need to recognize HoverMove. this->widget->setAttribute(Qt::WA_Hover, true); } }
Introduction of Control
- More than 160 exquisite controls, covering a variety of dashboards, progress bars, progress balls, compasses, curves, rulers, thermometers, navigation bars, navigation bars, flatui, highlighted buttons, sliding selectors, the lunar calendar and so on. Far more controls than qwt integrates.
- Each class can be separated into a separate control, zero-coupling, each control has a header file and an implementation file, independent of other files, to facilitate the integration of a single control in the form of source code into the project, less code. The control classes of qwt are interlinked and highly coupled. If you want to use one of the controls, you must include all the code.
- All pure Qt writing, QWidget+QPainter drawing, support any Qt version from Qt4.6 to Qt5.13, support mingw, msvc, gcc and other compilers, support any operating system such as windows+linux+mac + embedded linux, no scrambling, can be directly integrated into Qt Creator, as with its own controls, most of the effects can be set as few attributes, very convenient.
- Each control has a corresponding separate DEMO containing the source code of the control, which is convenient for reference. It also provides an integrated DEMO for all controls.
- The source code of each control has detailed Chinese annotations, which are compiled in accordance with the unified design specifications. It is convenient to learn how to compile custom controls.
- Each control's default color matching and demo's corresponding color matching are very beautiful.
- More than 130 visible controls and 6 invisible controls.
- Some controls provide a variety of style choices, a variety of indicator style choices.
- All controls adapt to form stretching changes.
- Integrate custom control property designer, support drag design, WYSIWYG, support import and export xml format.
- With activex control demo, all controls can run directly in ie browser.
- Integrate fontawesome graphic fonts + hundreds of graphic fonts collected by Alibaba iconfont to enjoy the fun of graphic fonts.
- All controls eventually generate a dynamic library file (dll or so, etc.) that can be directly integrated into the qtcreator to drag the design to use.
- At present, there is a version of qml, pyqt version will be considered later, if the user demand is large.
- Custom Control Plug-in Open Dynamic Library (permanently free), without any backdoor and restrictions, please feel free to use.
- At present, 32 versions of dll have been provided, of which qt_5_7_0_mingw530_32 will always guarantee the latest integrity.
- Increase control and improve control from time to time, update SDK from time to time. Welcome to make suggestions. Thank you!
- Qt introductory books recommend Hoyafei's Quick Start to Qt Creator, Qt5 Programming Introduction, and Qt advanced books recommend the official C++ GUI Qt4 Programming.
- I strongly recommend programmers'self-cultivation and planning series "Talking about Programmers", "Programmers' Growth Course" and "Solution Programmers". They benefit a lot and benefit a lifetime!
- SDK address: https://gitee.com/feiyangqingyun/QUCSDK https://github.com/feiyangqingyun/qucsdk