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 ?
QtWS25 Last Chance

Make a frameless QWidget resizable with QRubberBand ?

Scheduled Pinned Locked Moved Solved General and Desktop
qwidgetresizeframeless
19 Posts 3 Posters 14.7k Views
  • 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.
  • I Offline
    I Offline
    IMAN4K
    wrote on 30 Apr 2016, 03:37 last edited by IMAN4K
    #1

    Hi.
    I'm going to add resize functionality to my QWidget (with flag Qt::FramelessWindowHint) but without QSizeGrip

    I know that :

    I need a QRubberBand member
    I Should reimplement eventFilter()
    installEventFilter() in my class
    Handle mouseEvent (Hover,Leave,..) + calculate cursor position and then change the cursor shape
    resize() my QWidget to new drag point

    But here are some problem i face to :

    Should i installEventFilter() for my class (this) or my QRubberBand member?(process the events for QRubberBand or Qwidget? )
    How should i set QRubberBand to my QWidget class?(How should use QRubberBand )
    how change the QRubberBand weight ?(cursor change area)

    what i have tried already (but nothing happedn !) :
    .h

    class Sample : public QWidget {
        Q_OBJECT
    
    public:
        explicit Sample();
        ~Sample();
    
    private:
        QRubberBand *_rubberband;
        enum Edge
        {
            None,
            Top,
            Bottom,
            Left,
            Right,
            TopLeft,
            TopRight,
            BottomLeft,
            BottomRight
        };
        Edge _edge;
        bool _cursorchanged;
        qint16 _borderWidth;
    
    private:
        void Sample::hoverMoveEvent(QHoverEvent *e);
        void Sample::leaveMoveEvent(QEvent *e);
        void Sample::updateCursorShape(const QPoint &pos);
        void Sample::calculateCursorPosition(const QPoint &pos);
    
    protected:
        virtual bool eventFilter(QObject *o, QEvent *e);
    };
    

    .cpp

    Sample::Sample():
    _edge(None),
    _cursorchanged(false),
    _borderWidth(5)
    {
        setMouseTracking(true);
        setWindowFlags(Qt::FramelessWindowHint);
        _rubberband = NULL;
        installEventFilter(this);
    }
    
    Sample::~Sample() {}
    
    bool Sample::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())
            {
            default:
                break;
            case QEvent::MouseMove:
                //mouseMoveEvent(static_cast<QMouseEvent*>(e));
                break;
            case QEvent::HoverMove:
                hoverMoveEvent(static_cast<QHoverEvent*>(e));
                break;
            case QEvent::Leave:
                leaveMoveEvent(e);
                break;
            case QEvent::MouseButtonPress:
                //mouseButtonPress(static_cast<QMouseEvent*>(e));
                break;
            case QEvent::MouseButtonRelease:
                //mouseButtonRealese(static_cast<QMouseEvent*>(e));
                break;
            }
        }
        return false;
    }
    
    void Sample::hoverMoveEvent(QHoverEvent *e) {
        updateCursorShape(mapToGlobal(e->pos()));
    }
    
    void Sample::leaveMoveEvent(QEvent *e) {
            unsetCursor();
    }
    
    void Sample::updateCursorShape(const QPoint &pos) {
        if (isFullScreen() || isMaximized()) { unsetCursor(); return; }
        calculateCursorPosition((pos));
        if (_edge == TopLeft || _edge == BottomRight) {
            setCursor(Qt::SizeFDiagCursor);
            _cursorchanged = true;
        }
        else if (_edge == TopRight || _edge == BottomLeft) {
            setCursor(Qt::SizeBDiagCursor);
            _cursorchanged = true;
        }
        else if (_edge == Right || _edge == Left) {
            setCursor(Qt::SizeHorCursor);
            _cursorchanged = true;
        }
        else if (_edge == Top || _edge == Bottom) {
            setCursor(Qt::SizeVerCursor);
            _cursorchanged = true;
        }
        else {
            _cursorchanged = false;
            unsetCursor();
        }
    }
    
    void Sample::calculateCursorPosition(const QPoint &pos) {
        // Calculate cursor position based on frameGeometry() ,pos and _borderWidth
    }
    
    1 Reply Last reply
    0
    • M Offline
      M Offline
      mrjj
      Lifetime Qt Champion
      wrote on 30 Apr 2016, 09:57 last edited by mrjj
      #2

      @IMAN4K said:
      Hi
      If you see the docs
      http://doc.qt.io/qt-5/qrubberband.html#details
      it shows how rubberband is used.
      Its has no drag to resize build in. ( by it self)
      It is simply set by the user of the Band.
      So in mousePress, we make a band
      in mouseMove we set the geometry
      and on mouseRelease we use the rect, we just dragged.

      So you need not to use eventfilter since you can override the mouseXXX functions
      and handle it directly. So if you only have one custom widget, no real need to use
      filters.

      But, you must implement the resize your self. for your widget. The Rubberband
      is only for visual clues to uses.

      So when user Press and Drag in corner of widget, you must adjust the Geometry to match.
      and also update the Band so it still fits.

      I 1 Reply Last reply 30 Apr 2016, 11:51
      2
      • M mrjj
        30 Apr 2016, 09:57

        @IMAN4K said:
        Hi
        If you see the docs
        http://doc.qt.io/qt-5/qrubberband.html#details
        it shows how rubberband is used.
        Its has no drag to resize build in. ( by it self)
        It is simply set by the user of the Band.
        So in mousePress, we make a band
        in mouseMove we set the geometry
        and on mouseRelease we use the rect, we just dragged.

        So you need not to use eventfilter since you can override the mouseXXX functions
        and handle it directly. So if you only have one custom widget, no real need to use
        filters.

        But, you must implement the resize your self. for your widget. The Rubberband
        is only for visual clues to uses.

        So when user Press and Drag in corner of widget, you must adjust the Geometry to match.
        and also update the Band so it still fits.

        I Offline
        I Offline
        IMAN4K
        wrote on 30 Apr 2016, 11:51 last edited by
        #3

        @mrjj
        Thanks for Attention.
        I get all you say and know what to do but :
        My Widget is actually a base Widget for a Custom Window so it has a Titlebar and i think eventFilter() is good. isn't it ?
        Another thing is about cursor changing.i need a space area (just say weight of 5) around my Widget so when Hover happen (and leave also) cursor must be change.
        How to achieve this?

        M 1 Reply Last reply 30 Apr 2016, 12:03
        0
        • I IMAN4K
          30 Apr 2016, 11:51

          @mrjj
          Thanks for Attention.
          I get all you say and know what to do but :
          My Widget is actually a base Widget for a Custom Window so it has a Titlebar and i think eventFilter() is good. isn't it ?
          Another thing is about cursor changing.i need a space area (just say weight of 5) around my Widget so when Hover happen (and leave also) cursor must be change.
          How to achieve this?

          M Offline
          M Offline
          mrjj
          Lifetime Qt Champion
          wrote on 30 Apr 2016, 12:03 last edited by
          #4

          @IMAN4K

          • and i think eventFilter() is good. isn't it ?
            Its fine and ok to use if u prefer over the mouseX methods.

          • .i need a space area (just say weight of 5) around my Widget

          One way to do this is via a layout. IF you add layout to window, and set
          contentsMargins u can get such free area.
          http://doc.qt.io/qt-5/qlayout.html#contentsMargins

          I 1 Reply Last reply 30 Apr 2016, 12:56
          1
          • M mrjj
            30 Apr 2016, 12:03

            @IMAN4K

            • and i think eventFilter() is good. isn't it ?
              Its fine and ok to use if u prefer over the mouseX methods.

            • .i need a space area (just say weight of 5) around my Widget

            One way to do this is via a layout. IF you add layout to window, and set
            contentsMargins u can get such free area.
            http://doc.qt.io/qt-5/qlayout.html#contentsMargins

            I Offline
            I Offline
            IMAN4K
            wrote on 30 Apr 2016, 12:56 last edited by
            #5

            @mrjj
            Is there another way for that area ?
            Because if i implement mouseX events for my Widget and if cursor change happen, all around my widget cursor stay the same and i need that changing just for that edge area

            M 1 Reply Last reply 30 Apr 2016, 13:13
            0
            • I IMAN4K
              30 Apr 2016, 12:56

              @mrjj
              Is there another way for that area ?
              Because if i implement mouseX events for my Widget and if cursor change happen, all around my widget cursor stay the same and i need that changing just for that edge area

              M Offline
              M Offline
              mrjj
              Lifetime Qt Champion
              wrote on 30 Apr 2016, 13:13 last edited by
              #6

              @IMAN4K
              Hi
              Im not sure of the issue
              if mouse goes into area, u set it, if it leaves are u reset.
              You can check in mouseMove if it leaves the area moving further into the widget.

              so im not sure what ", all around my widget cursor stay the same"
              means ?

              I 1 Reply Last reply 30 Apr 2016, 17:53
              1
              • M mrjj
                30 Apr 2016, 13:13

                @IMAN4K
                Hi
                Im not sure of the issue
                if mouse goes into area, u set it, if it leaves are u reset.
                You can check in mouseMove if it leaves the area moving further into the widget.

                so im not sure what ", all around my widget cursor stay the same"
                means ?

                I Offline
                I Offline
                IMAN4K
                wrote on 30 Apr 2016, 17:53 last edited by
                #7

                @mrjj said:

                One way to do this is via a layout. IF you add layout to window, and set
                contentsMargins u can get such free area

                I'm confusing about this solution.
                That require area i have mentioned must receivemouseEvents and you said you must set a Layout so Can Layouts receive mouseEvent ?

                @mrjj said:

                so im not sure what ", all around my widget cursor stay the same"
                means ?

                I mean if i implement mouseEvent for my widget after hovering cursor will change at the edge of my widget
                it's good but if keep moving to widget(not leave the widget area) cursor will stay the same and will not change while cursor must return to arrow state if it pass that weight (5)

                I hope i have been clear.

                M 1 Reply Last reply 30 Apr 2016, 22:08
                0
                • I IMAN4K
                  30 Apr 2016, 17:53

                  @mrjj said:

                  One way to do this is via a layout. IF you add layout to window, and set
                  contentsMargins u can get such free area

                  I'm confusing about this solution.
                  That require area i have mentioned must receivemouseEvents and you said you must set a Layout so Can Layouts receive mouseEvent ?

                  @mrjj said:

                  so im not sure what ", all around my widget cursor stay the same"
                  means ?

                  I mean if i implement mouseEvent for my widget after hovering cursor will change at the edge of my widget
                  it's good but if keep moving to widget(not leave the widget area) cursor will stay the same and will not change while cursor must return to arrow state if it pass that weight (5)

                  I hope i have been clear.

                  M Offline
                  M Offline
                  mrjj
                  Lifetime Qt Champion
                  wrote on 30 Apr 2016, 22:08 last edited by
                  #8

                  @IMAN4K

                  • Can Layouts receive mouseEvent ?
                    They should go to the Window Widget. or class that handles the
                    cursor change.

                  • cursor must return to arrow state if it pass that weight (5)
                    I guess detecting it by using mouseMove is too unreliable.

                  have you check if
                  http://doc.qt.io/qt-5/qwidget.html#leaveEvent
                  could be used?

                  1 Reply Last reply
                  1
                  • I Offline
                    I Offline
                    IMAN4K
                    wrote on 3 May 2016, 17:48 last edited by IMAN4K 5 Mar 2016, 18:31
                    #9

                    @mrjj
                    I think i finally figured it out ;)
                    But can you look at my code please :

                    class Widget : public QWidget {
                    	Q_OBJECT
                    
                    public:
                    	explicit Widget();
                    	~Widget();
                    	void setBorderWidth(const qint16 &borderWidth);
                    
                    private:
                    	enum Edge
                    	{
                    		None,
                    		Top,
                    		Bottom,
                    		Left,
                    		Right,
                    		TopLeft,
                    		TopRight,
                    		BottomLeft,
                    		BottomRight
                    	};
                    	QRubberBand *_rubberband;
                    	bool _cursorchanged;
                    	bool _leftButtonPressed;
                    	qint16 _borderWidth;
                    	Edge _edge;
                    
                    private:
                    	void mouseHover(QHoverEvent *e);
                    	void mouseLeave(QEvent *e);
                    	void mousePress(QMouseEvent *e);
                    	void mouseRealese(QMouseEvent *e);
                    	void mouseMove(QMouseEvent *e);
                    	void updateCursorShape(const QPoint &pos);
                    	void calculateCursorPosition(const QPoint &pos);
                    	void updateRubberBand();
                    
                    protected:
                    	void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;
                    	bool eventFilter(QObject *o, QEvent *e) Q_DECL_OVERRIDE;
                    };
                    
                    Widget::Widget() :
                    _cursorchanged(false),
                    _borderWidth(4),
                    _edge(None),
                    _leftButtonPressed(false),
                    _rubberband(0)
                    {
                    	setMouseTracking(true);
                    	setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
                    	setAttribute(Qt::WA_Hover);
                    	setAttribute(Qt::WA_TranslucentBackground);
                    	installEventFilter(this);
                    }
                    
                    Widget::~Widget() {}
                    
                    void Widget::paintEvent(QPaintEvent *) {
                    	QPainter painter(this);
                    	painter.setBrush(QColor("#FFFFFF"));
                    	painter.setPen(Qt::NoPen);
                    	painter.setRenderHint(QPainter::Antialiasing);
                    
                    	QPainterPath path;
                    	path.addRoundedRect(QRect(0, 0, width(), height()), 5.0, 5.0);
                    	painter.drawPath(path.simplified());
                    }
                    
                    bool Widget::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())
                    		{
                    		default:
                    			break;
                    		case QEvent::MouseMove:
                    			mouseMove(static_cast<QMouseEvent*>(e));
                    			break;
                    		case QEvent::HoverMove:
                    			mouseHover(static_cast<QHoverEvent*>(e));
                    			break;
                    		case QEvent::Leave:
                    			mouseLeave(e);
                    			break;
                    		case QEvent::MouseButtonPress:
                    			mousePress(static_cast<QMouseEvent*>(e));
                    			break;
                    		case QEvent::MouseButtonRelease:
                    			mouseRealese(static_cast<QMouseEvent*>(e));
                    			break;
                    		}
                    	}
                    	return false;
                    }
                    
                    void Widget::mouseHover(QHoverEvent *e) {
                    	updateCursorShape(mapToGlobal(e->pos()));
                    
                    }
                    
                    void Widget::mouseLeave(QEvent *e) {
                    	Q_UNUSED(e);
                    	unsetCursor();
                    }
                    
                    void Widget::mousePress(QMouseEvent *e) {
                    	if (e->buttons() && Qt::LeftButton) {
                    		_leftButtonPressed = true;
                    		if (_edge != None) {
                    			updateRubberBand();
                    			_rubberband->setGeometry(frameGeometry().x(), frameGeometry().y(), frameGeometry().width(), frameGeometry().height());
                    		}
                    	}
                    }
                    
                    void Widget::mouseRealese(QMouseEvent *e) {
                    		_leftButtonPressed = false;
                    		_edge = None;
                    		if (_rubberband) {
                    			updateRubberBand();
                    		}
                    }
                    
                    void Widget::mouseMove(QMouseEvent *e) {
                    	if (_leftButtonPressed && _edge != None) {
                    		QRect originalRect = _rubberband->frameGeometry();
                    		int left = originalRect.left();
                    		int top = originalRect.top();
                    		int right = originalRect.right();
                    		int bottom = originalRect.bottom();
                    		if (_edge == Top) {
                    			top = e->globalPos().y();
                    		} else if (_edge == Bottom) {
                    			bottom = e->globalPos().y();
                    		} else if (_edge == Left) {
                    			left = e->globalPos().x();
                    		} else if (_edge == Right) {
                    			right = e->globalPos().x();
                    		} else if (_edge == TopLeft) {
                    			left = e->globalPos().x();
                    			top = e->globalPos().y();
                    		} else if (_edge == TopRight) {
                    			top = e->globalPos().y();
                    			right = e->globalPos().x();
                    		} else if (_edge == BottomLeft) {
                    			left = e->globalPos().x();
                    			bottom = e->globalPos().y();
                    		} else if (_edge == BottomRight) {
                    			bottom = e->globalPos().y();
                    			right = e->globalPos().x();
                    		}
                    		_rubberband->setGeometry(QRect(QPoint(left, top), QPoint(right, bottom)));
                    		setGeometry(_rubberband->geometry());
                    	}
                    }
                    
                    void Widget::updateCursorShape(const QPoint &pos) {
                    	if (isFullScreen() || isMaximized()) { 
                    		if (_cursorchanged) {
                    			unsetCursor();
                    			return;
                    		}
                    	}
                    	calculateCursorPosition((pos));
                    	if (_edge == TopLeft || _edge == BottomRight) {
                    		setCursor(Qt::SizeFDiagCursor);
                    		_cursorchanged = true;
                    	} else if (_edge == TopRight || _edge == BottomLeft) {
                    		setCursor(Qt::SizeBDiagCursor);
                    		_cursorchanged = true;
                    	} else if (_edge == Right || _edge == Left) {
                    		setCursor(Qt::SizeHorCursor);
                    		_cursorchanged = true;
                    	} else if (_edge == Top || _edge == Bottom) {
                    		setCursor(Qt::SizeVerCursor);
                    		_cursorchanged = true;
                    	} else if (_cursorchanged) {
                    		_cursorchanged = false;
                    		unsetCursor();
                    	}
                    	
                    }
                    
                    void Widget::calculateCursorPosition(const QPoint &pos) {
                    	bool onLeft = pos.x() <= frameGeometry().x() + _borderWidth && pos.x() >= frameGeometry().x() &&
                    		pos.y() <= frameGeometry().y() + frameGeometry().height() - _borderWidth && pos.y() >= frameGeometry().y() + _borderWidth;
                    
                    	bool onRight = pos.x() >= frameGeometry().x() + frameGeometry().width() - _borderWidth && pos.x() <= frameGeometry().x() + frameGeometry().width() &&
                    		pos.y() >= frameGeometry().y() + _borderWidth && pos.y() <= frameGeometry().y() + frameGeometry().height() - _borderWidth - 2;
                    
                    	bool onBottom = pos.x() >= frameGeometry().x() + _borderWidth && pos.x() <= frameGeometry().x() + frameGeometry().width() - _borderWidth - 2 &&
                    		pos.y() >= frameGeometry().y() + frameGeometry().height() - _borderWidth && pos.y() <= frameGeometry().y() + frameGeometry().height();
                    
                    	bool onTop = pos.x() >= frameGeometry().x() + _borderWidth && pos.x() <= frameGeometry().x() + frameGeometry().width() - _borderWidth &&
                    		pos.y() >= frameGeometry().y() && pos.y() <= frameGeometry().y() + _borderWidth;
                    
                    	bool  onBottomleft = pos.x() <= frameGeometry().x() + _borderWidth && pos.x() >= frameGeometry().x() &&
                    		pos.y() <= frameGeometry().y() + frameGeometry().height() && pos.y() >= frameGeometry().y() + frameGeometry().height() - _borderWidth;
                    
                    	bool onBottomRight = pos.x() >= frameGeometry().x() + frameGeometry().width() - _borderWidth && pos.x() <= frameGeometry().x() + frameGeometry().width() &&
                    		pos.y() >= frameGeometry().y() + frameGeometry().height() - _borderWidth && pos.y() <= frameGeometry().y() + frameGeometry().height();
                    
                    	bool onTopRight = pos.x() >= frameGeometry().x() + frameGeometry().width() - _borderWidth && pos.x() <= frameGeometry().x() + frameGeometry().width() &&
                    		pos.y() >= frameGeometry().y() && pos.y() <= frameGeometry().y() + _borderWidth;
                    
                    	bool onTopLeft = pos.x() >= frameGeometry().x() && pos.x() <= frameGeometry().x() + _borderWidth &&
                    		pos.y() >= frameGeometry().y() && pos.y() <= frameGeometry().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 Widget::updateRubberBand() {
                    	if (!_rubberband) {
                    		_rubberband = new QRubberBand(QRubberBand::Rectangle);
                    	} else {
                    		delete _rubberband;
                    		_rubberband = 0;
                    	}
                    }
                    
                    void Widget::setBorderWidth(const qint16 &borderWidth) {
                    	_borderWidth = borderWidth;
                    }
                    

                    It work but for top edge and left edge it's not working as i expect !

                    1 Reply Last reply
                    2
                    • 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