Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Make a frameless QWidget resizable with QRubberBand ?
Forum Updated to NodeBB v4.3 + New Features

Make a frameless QWidget resizable with QRubberBand ?

Scheduled Pinned Locked Moved Solved General and Desktop
qwidgetresizeframeless
19 Posts 3 Posters 15.3k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    mrjj
    Lifetime Qt Champion
    wrote on 3 May 2016, 17:51 last edited by
    #10

    Hi
    Good work.
    So for top/left what happens?

    I 1 Reply Last reply 3 May 2016, 18:21
    1
    • M mrjj
      3 May 2016, 17:51

      Hi
      Good work.
      So for top/left what happens?

      I Offline
      I Offline
      IMAN4K
      wrote on 3 May 2016, 18:21 last edited by
      #11

      @mrjj
      It doesn't extend the widget from the top and left edge (+bottomLeft+topLeft+topRight) and i have no idea !
      https://drive.google.com/file/d/0BxRSkzkLrTjVX18wd0U4YWZnVms/view?pref=2&pli=1
      Thanks for your time.

      1 Reply Last reply
      0
      • M Offline
        M Offline
        mrjj
        Lifetime Qt Champion
        wrote on 3 May 2016, 18:27 last edited by
        #12

        Ok
        First. good job. Seem to work great.
        I can see that dragging up seems not to work but
        did not spot anything looking at code.

        Is the code complete?
        I can run it if I put in a default project?

        I 1 Reply Last reply 3 May 2016, 18:32
        1
        • M mrjj
          3 May 2016, 18:27

          Ok
          First. good job. Seem to work great.
          I can see that dragging up seems not to work but
          did not spot anything looking at code.

          Is the code complete?
          I can run it if I put in a default project?

          I Offline
          I Offline
          IMAN4K
          wrote on 3 May 2016, 18:32 last edited by IMAN4K 5 Mar 2016, 18:33
          #13

          @mrjj

          Is the code complete?

          Yes It's complete

          M 1 Reply Last reply 3 May 2016, 18:45
          0
          • I IMAN4K
            3 May 2016, 18:32

            @mrjj

            Is the code complete?

            Yes It's complete

            M Offline
            M Offline
            mrjj
            Lifetime Qt Champion
            wrote on 3 May 2016, 18:45 last edited by
            #14

            @IMAN4K
            Yep. Besides some #include it ran.

            The reason up dont work is that it adjust the window the wrong way
            (y++) so when u drag up, it goes down 1 pixel and then mouse is outside and the drag stops.

            Not sure where the actual error is yet. Seems to be need minus and not plus
            for drag that way.

            I 1 Reply Last reply 4 May 2016, 16:31
            1
            • M mrjj
              3 May 2016, 18:45

              @IMAN4K
              Yep. Besides some #include it ran.

              The reason up dont work is that it adjust the window the wrong way
              (y++) so when u drag up, it goes down 1 pixel and then mouse is outside and the drag stops.

              Not sure where the actual error is yet. Seems to be need minus and not plus
              for drag that way.

              I Offline
              I Offline
              IMAN4K
              wrote on 4 May 2016, 16:31 last edited by
              #15

              @mrjj
              Still no idea ?
              I'm really stuck !

              M 1 Reply Last reply 5 May 2016, 06:01
              0
              • I IMAN4K
                4 May 2016, 16:31

                @mrjj
                Still no idea ?
                I'm really stuck !

                M Offline
                M Offline
                mrjj
                Lifetime Qt Champion
                wrote on 5 May 2016, 06:01 last edited by
                #16

                @IMAN4K
                Sorry. nope.
                Nothing jumped to mind.

                Did you qDebug the points used for adjusting Geometry ?
                To see how values are when is the Top case?

                1 Reply Last reply
                2
                • I Offline
                  I Offline
                  IMAN4K
                  wrote on 7 May 2016, 05:32 last edited by IMAN4K
                  #17

                  Thanks @mrjj for all answers.
                  You were right calculating was mistake
                  I just used an inner space for calculating mouse area but you also need to consider an outer area (the green border) :
                  https://onedrive.live.com/redir?resid=8882D1E3BC0F61AB!7402&authkey=!ACT6umOQeAEcN7A&v=3&ithint=photo%2Cjpg
                  Here for any one else :

                  frameless.h:

                  #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 {
                  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 *parent);
                  
                  	void setBorderWidth(int);
                  	int borderWidth() const;
                  
                  	QWidget *_parent = nullptr;
                  	QRubberBand *_rubberband = nullptr;
                  	bool _cursorchanged;
                  	bool _leftButtonPressed;
                  	Edges _mousePress = Edge::None;
                  	Edges _mouseMove = Edge::None;
                  	int _borderWidth;
                  
                  	QPoint _dragPos;
                  	bool _dragStart = false;
                  
                  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 &);
                  };
                  
                  Q_DECLARE_OPERATORS_FOR_FLAGS(FrameLess::Edges);
                  

                  frameless.cpp:

                  #include "FrameLess.h"
                  
                  FrameLess::FrameLess(QWidget *parent) :
                  _parent(parent),
                  _cursorchanged(false),
                  _leftButtonPressed(false),
                  _borderWidth(5),
                  _dragPos(QPoint())
                  {
                  	_parent->setMouseTracking(true);
                  	_parent->setWindowFlags(Qt::FramelessWindowHint);
                  	_parent->setAttribute(Qt::WA_Hover);
                  	_parent->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 _parent->eventFilter(o, e);
                  	}
                  }
                  
                  void FrameLess::mouseHover(QHoverEvent *e) {
                  	updateCursorShape(_parent->mapToGlobal(e->pos()));
                  }
                  
                  void FrameLess::mouseLeave(QEvent *e) {
                  	if (!_leftButtonPressed) {
                  		_parent->unsetCursor();
                  	}
                  }
                  
                  void FrameLess::mousePress(QMouseEvent *e) {
                  	if (e->button() & Qt::LeftButton) {
                  		_leftButtonPressed = true;
                  		calculateCursorPosition(e->globalPos(), _parent->frameGeometry(), _mousePress);
                  		if (!_mousePress.testFlag(Edge::None)) {
                  			_rubberband->setGeometry(_parent->frameGeometry());
                  		}
                  		if (_parent->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) {
                  			_parent->move(_parent->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() < _parent->minimumWidth()) {
                  				left = _parent->frameGeometry().x();
                  			} else if (newRect.height() < _parent->minimumHeight()) {
                  				top = _parent->frameGeometry().y();
                  			}
                  			_parent->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 (_parent->isFullScreen() || _parent->isMaximized()) {
                  		if (_cursorchanged) {
                  			_parent->unsetCursor();
                  		}
                  		return;
                  	}
                  	if (!_leftButtonPressed) {
                  		calculateCursorPosition(pos, _parent->frameGeometry(), _mouseMove);
                  		_cursorchanged = true;
                  		if (_mouseMove.testFlag(Edge::Top) || _mouseMove.testFlag(Edge::Bottom)) {
                  			_parent->setCursor(Qt::SizeVerCursor);
                  		} else if (_mouseMove.testFlag(Edge::Left) || _mouseMove.testFlag(Edge::Right)) {
                  			_parent->setCursor(Qt::SizeHorCursor);
                  		} else if (_mouseMove.testFlag(Edge::TopLeft) || _mouseMove.testFlag(Edge::BottomRight)) {
                  			_parent->setCursor(Qt::SizeFDiagCursor);
                  		} else if (_mouseMove.testFlag(Edge::TopRight) || _mouseMove.testFlag(Edge::BottomLeft)) {
                  			_parent->setCursor(Qt::SizeBDiagCursor);
                  		} else if (_cursorchanged) {
                  			_parent->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;
                  	}
                  }
                  
                  void FrameLess::setBorderWidth(int borderWidth) {
                  	_borderWidth = borderWidth;
                  }
                  
                  int FrameLess::borderWidth() const {
                  	return _borderWidth;
                  }
                  
                  1 Reply Last reply
                  1
                  • M Offline
                    M Offline
                    mrjj
                    Lifetime Qt Champion
                    wrote on 7 May 2016, 07:30 last edited by
                    #18

                    Good found.
                    Thx for reporting back.
                    Im sure someone will re-use this some day.

                    1 Reply Last reply
                    0
                    • W Offline
                      W Offline
                      wrekler
                      wrote on 11 Oct 2018, 23:50 last edited by
                      #19

                      I found very usefull this class, I added some code to handle correctly a maximized FrameLess Widget.
                      In

                      void FrameLess::mouseMove(QMouseEvent *e) {
                      	if (_dragStart) {
                      		if (_parent->isMaximized()) { //this will handle correctly dragging when it is maximized
                      			maximizeWidth = _parent->width(); //maximizeWidth is an int attribute
                      			_parent->showNormal();
                      		}
                      		if (_dragPos.x() > _parent->width())
                      			_dragPos.setX((_parent->width()*_dragPos.x()) / maximizeWidth);
                      		_parent->move(e->globalX() - _dragPos.x(), e->globalY() - _dragPos.y());
                      	}
                      	if (!_mousePress.testFlag(Edge::None) && !_parent->isMaximized() ) { //this prevent resizing if it is maximized
                      		[...]
                      

                      Now I'm wondering if there is a way to implement Windows 7/10 autosize function (the function when you drag a window on top/left/right/bottom edge of desktop and it will maximize/resize to half desktop size) on a frameless widget!

                      1 Reply Last reply
                      1

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved