Created
October 6, 2017 11:25
-
-
Save Nico-Duduf/b8c799f1f2a694732abd1238843b1d70 to your computer and use it in GitHub Desktop.
Qt - Resizable frameless widget
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "frameless.h" | |
FrameLess::FrameLess(QWidget *target) : | |
_target(target), | |
_cursorchanged(false), | |
_leftButtonPressed(false), | |
_borderWidth(5), | |
_dragPos(QPoint()) | |
{ | |
_target->setMouseTracking(true); | |
_target->setWindowFlags(Qt::FramelessWindowHint); | |
_target->setAttribute(Qt::WA_Hover); | |
_target->installEventFilter(this); | |
_rubberband = new QRubberBand(QRubberBand::Rectangle); | |
} | |
bool FrameLess::eventFilter(QObject *o, QEvent*e) { | |
if (e->type() == QEvent::MouseMove || | |
e->type() == QEvent::HoverMove || | |
e->type() == QEvent::Leave || | |
e->type() == QEvent::MouseButtonPress || | |
e->type() == QEvent::MouseButtonRelease) { | |
switch (e->type()) { | |
case QEvent::MouseMove: | |
mouseMove(static_cast<QMouseEvent*>(e)); | |
return true; | |
break; | |
case QEvent::HoverMove: | |
mouseHover(static_cast<QHoverEvent*>(e)); | |
return true; | |
break; | |
case QEvent::Leave: | |
mouseLeave(e); | |
return true; | |
break; | |
case QEvent::MouseButtonPress: | |
mousePress(static_cast<QMouseEvent*>(e)); | |
return true; | |
break; | |
case QEvent::MouseButtonRelease: | |
mouseRealese(static_cast<QMouseEvent*>(e)); | |
return true; | |
break; | |
} | |
} | |
else { | |
return _target->eventFilter(o, e); | |
} | |
} | |
void FrameLess::mouseHover(QHoverEvent *e) { | |
updateCursorShape(_target->mapToGlobal(e->pos())); | |
} | |
void FrameLess::mouseLeave(QEvent *e) { | |
if (!_leftButtonPressed) { | |
_target->unsetCursor(); | |
} | |
} | |
void FrameLess::mousePress(QMouseEvent *e) { | |
if (e->button() & Qt::LeftButton) { | |
_leftButtonPressed = true; | |
calculateCursorPosition(e->globalPos(), _target->frameGeometry(), _mousePress); | |
if (!_mousePress.testFlag(Edge::None)) { | |
_rubberband->setGeometry(_target->frameGeometry()); | |
} | |
if (_target->rect().marginsRemoved(QMargins(borderWidth(), borderWidth(), borderWidth(), borderWidth())).contains(e->pos())) { | |
_dragStart = true; | |
_dragPos = e->pos(); | |
} | |
} | |
} | |
void FrameLess::mouseRealese(QMouseEvent *e) { | |
if (e->button() & Qt::LeftButton) { | |
_leftButtonPressed = false; | |
_dragStart = false; | |
} | |
} | |
void FrameLess::mouseMove(QMouseEvent *e) { | |
if (_leftButtonPressed) { | |
if (_dragStart) { | |
_target->move(_target->frameGeometry().topLeft() + (e->pos() - _dragPos)); | |
} | |
if (!_mousePress.testFlag(Edge::None)) { | |
int left = _rubberband->frameGeometry().left(); | |
int top = _rubberband->frameGeometry().top(); | |
int right = _rubberband->frameGeometry().right(); | |
int bottom = _rubberband->frameGeometry().bottom(); | |
switch (_mousePress) { | |
case Edge::Top: | |
top = e->globalPos().y(); | |
break; | |
case Edge::Bottom: | |
bottom = e->globalPos().y(); | |
break; | |
case Edge::Left: | |
left = e->globalPos().x(); | |
break; | |
case Edge::Right: | |
right = e->globalPos().x(); | |
break; | |
case Edge::TopLeft: | |
top = e->globalPos().y(); | |
left = e->globalPos().x(); | |
break; | |
case Edge::TopRight: | |
right = e->globalPos().x(); | |
top = e->globalPos().y(); | |
break; | |
case Edge::BottomLeft: | |
bottom = e->globalPos().y(); | |
left = e->globalPos().x(); | |
break; | |
case Edge::BottomRight: | |
bottom = e->globalPos().y(); | |
right = e->globalPos().x(); | |
break; | |
} | |
QRect newRect(QPoint(left, top), QPoint(right, bottom)); | |
if (newRect.width() < _target->minimumWidth()) { | |
left = _target->frameGeometry().x(); | |
} | |
else if (newRect.height() < _target->minimumHeight()) { | |
top = _target->frameGeometry().y(); | |
} | |
_target->setGeometry(QRect(QPoint(left, top), QPoint(right, bottom))); | |
_rubberband->setGeometry(QRect(QPoint(left, top), QPoint(right, bottom))); | |
} | |
} | |
else { | |
updateCursorShape(e->globalPos()); | |
} | |
} | |
void FrameLess::updateCursorShape(const QPoint &pos) { | |
if (_target->isFullScreen() || _target->isMaximized()) { | |
if (_cursorchanged) { | |
_target->unsetCursor(); | |
} | |
return; | |
} | |
if (!_leftButtonPressed) { | |
calculateCursorPosition(pos, _target->frameGeometry(), _mouseMove); | |
_cursorchanged = true; | |
if (_mouseMove.testFlag(Edge::Top) || _mouseMove.testFlag(Edge::Bottom)) { | |
_target->setCursor(Qt::SizeVerCursor); | |
} | |
else if (_mouseMove.testFlag(Edge::Left) || _mouseMove.testFlag(Edge::Right)) { | |
_target->setCursor(Qt::SizeHorCursor); | |
} | |
else if (_mouseMove.testFlag(Edge::TopLeft) || _mouseMove.testFlag(Edge::BottomRight)) { | |
_target->setCursor(Qt::SizeFDiagCursor); | |
} | |
else if (_mouseMove.testFlag(Edge::TopRight) || _mouseMove.testFlag(Edge::BottomLeft)) { | |
_target->setCursor(Qt::SizeBDiagCursor); | |
} | |
else if (_cursorchanged) { | |
_target->unsetCursor(); | |
_cursorchanged = false; | |
} | |
} | |
} | |
void FrameLess::calculateCursorPosition(const QPoint &pos, const QRect &framerect, Edges &_edge) { | |
bool onLeft = pos.x() >= framerect.x() - _borderWidth && pos.x() <= framerect.x() + _borderWidth && | |
pos.y() <= framerect.y() + framerect.height() - _borderWidth && pos.y() >= framerect.y() + _borderWidth; | |
bool onRight = pos.x() >= framerect.x() + framerect.width() - _borderWidth && pos.x() <= framerect.x() + framerect.width() && | |
pos.y() >= framerect.y() + _borderWidth && pos.y() <= framerect.y() + framerect.height() - _borderWidth; | |
bool onBottom = pos.x() >= framerect.x() + _borderWidth && pos.x() <= framerect.x() + framerect.width() - _borderWidth && | |
pos.y() >= framerect.y() + framerect.height() - _borderWidth && pos.y() <= framerect.y() + framerect.height(); | |
bool onTop = pos.x() >= framerect.x() + _borderWidth && pos.x() <= framerect.x() + framerect.width() - _borderWidth && | |
pos.y() >= framerect.y() && pos.y() <= framerect.y() + _borderWidth; | |
bool onBottomLeft = pos.x() <= framerect.x() + _borderWidth && pos.x() >= framerect.x() && | |
pos.y() <= framerect.y() + framerect.height() && pos.y() >= framerect.y() + framerect.height() - _borderWidth; | |
bool onBottomRight = pos.x() >= framerect.x() + framerect.width() - _borderWidth && pos.x() <= framerect.x() + framerect.width() && | |
pos.y() >= framerect.y() + framerect.height() - _borderWidth && pos.y() <= framerect.y() + framerect.height(); | |
bool onTopRight = pos.x() >= framerect.x() + framerect.width() - _borderWidth && pos.x() <= framerect.x() + framerect.width() && | |
pos.y() >= framerect.y() && pos.y() <= framerect.y() + _borderWidth; | |
bool onTopLeft = pos.x() >= framerect.x() && pos.x() <= framerect.x() + _borderWidth && | |
pos.y() >= framerect.y() && pos.y() <= framerect.y() + _borderWidth; | |
if (onLeft) { | |
_edge = Left; | |
} | |
else if (onRight) { | |
_edge = Right; | |
} | |
else if (onBottom) { | |
_edge = Bottom; | |
} | |
else if (onTop) { | |
_edge = Top; | |
} | |
else if (onBottomLeft) { | |
_edge = BottomLeft; | |
} | |
else if (onBottomRight) { | |
_edge = BottomRight; | |
} | |
else if (onTopRight) { | |
_edge = TopRight; | |
} | |
else if (onTopLeft) { | |
_edge = TopLeft; | |
} | |
else { | |
_edge = None; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//seen at https://stackoverflow.com/questions/5752408/qt-resize-borderless-widget/37507341#37507341 | |
//posted by https://stackoverflow.com/users/5446734/iman4k | |
#pragma once | |
#include <QtWidgets/QWidget> | |
#include <QtWidgets/QRubberBand> | |
#include <QtCore/QObject> | |
#include <QtCore/QEvent> | |
#include <QtCore/QRect> | |
#include <QtCore/QPoint> | |
#include <QtCore/Qt> | |
#include <QtGui/QHoverEvent> | |
#include <QtGui/QMouseEvent> | |
class FrameLess : public QObject { | |
Q_OBJECT | |
public: | |
enum Edge { | |
None = 0x0, | |
Left = 0x1, | |
Top = 0x2, | |
Right = 0x4, | |
Bottom = 0x8, | |
TopLeft = 0x10, | |
TopRight = 0x20, | |
BottomLeft = 0x40, | |
BottomRight = 0x80, | |
}; | |
Q_ENUM(Edge); | |
Q_DECLARE_FLAGS(Edges, Edge); | |
FrameLess(QWidget *target); | |
void setBorderWidth(int w) { | |
_borderWidth = w; | |
} | |
int borderWidth() const { | |
return _borderWidth; | |
} | |
protected: | |
bool eventFilter(QObject *o, QEvent *e) override; | |
void mouseHover(QHoverEvent*); | |
void mouseLeave(QEvent*); | |
void mousePress(QMouseEvent*); | |
void mouseRealese(QMouseEvent*); | |
void mouseMove(QMouseEvent*); | |
void updateCursorShape(const QPoint &); | |
void calculateCursorPosition(const QPoint &, const QRect &, Edges &); | |
private: | |
QWidget *_target = nullptr; | |
QRubberBand *_rubberband = nullptr; | |
bool _cursorchanged; | |
bool _leftButtonPressed; | |
Edges _mousePress = Edge::None; | |
Edges _mouseMove = Edge::None; | |
int _borderWidth; | |
QPoint _dragPos; | |
bool _dragStart = false; | |
}; | |
Q_DECLARE_OPERATORS_FOR_FLAGS(FrameLess::Edges); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "frameless.h" | |
#include <QtWidgets/qapplication.h> | |
int main(int argc, char *argv[]) { | |
QApplication a(argc, argv); | |
QWidget *widget = new QWidget; | |
FrameLess f(widget); | |
widget->show(); | |
return a.exec(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment