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. How to create a custom grip to resize widgets inside a layout?
Forum Updated to NodeBB v4.3 + New Features

How to create a custom grip to resize widgets inside a layout?

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 1.8k Views 2 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.
  • N Offline
    N Offline
    n34rt
    wrote on last edited by
    #1

    I created a label to behave as a grip, to be able to 'customize' the height of widgets that are inside of a QGridLayout.

    To get the resize working correctly with any kind of widget size, I needed to set both min and maximum height according to the mouse position relative to the grip:

                // Adapt the widget size based on mouse movement.
                QPoint delta = e->pos() - mousePos;
                mousePos = e->pos();
    
                if (delta.y())
                    parentHeight += delta.y();
                else
                    parentHeight -= delta.y();
                
                parent->setMinimumHeight(parentHeight);
                parent->setMaximumHeight(parentHeight);
    

    But this prevents the widget from growing together with her QGridLayout parent, as the MaximumHeight is limited.

    An example:

    After reducing the height of the GUI and then increasing it again, how I could make the red frame grow together with the blue frame?

    enter image description here

    I thought in "resetting" the setMaximumHeight at the mouseRelease event, then it could 'grow' again:

    void mouseReleaseEvent(QMouseEvent* e) { parent->setMaximumHeight(QWIDGETSIZE_MAX); }
    

    However, the widget is automatically adjusted by her QGridLayout parent:

    enter image description here

    Reproducible example as seen in the gif:

    // gripLabel.h
    class GripLabel : public QLabel
    {
        Q_OBJECT
    
    public:
    
        QGridLayout* layout;     
        QWidget* parent;
    
        bool resizing = false;
        QSize gripSize = QSize(20, 8);
        QPoint mousePos;
        
        int parentHeight = 0;
    
        GripLabel(QWidget* p = 0) : QLabel()
        {
            parent = p;
            layout = qobject_cast<QGridLayout*>(parent->layout());
    
            setMinimumWidth(20);
    
            // background-color: green
            // debug only, just to be able to see the grip area.
            this->setStyleSheet(R"(
                background-image: url(:/icons/sizegrip);
                background-repeat: no-repeat;
                background-position: bottom right;            
                background-color: green;
            )");
        }
    
        void mousePressEvent(QMouseEvent* e)
        {
            mousePos = e->pos();
            QPoint gripPos = QPoint(width() - gripSize.width(), 
                                    height() - gripSize.height());
    
            // Check if we hit the grip handle.
            if ((mousePos.x() >= gripPos.x()) && (mousePos.y() >= gripPos.y()))
            {
                parentHeight = parent->height();
                resizing = true;
            }
            else
                resizing = false;
        }
        
        void mouseReleaseEvent(QMouseEvent* e)
        {
            //parent->setMaximumHeight(QWIDGETSIZE_MAX);
        }
    
        void mouseMoveEvent(QMouseEvent* e)
        {
            if (resizing) 
            {
                // Adapt the widget size based on mouse movement.
                QPoint delta = e->pos() - mousePos;
                mousePos = e->pos();
    
                if (delta.y())
                    parentHeight += delta.y();
                else
                    parentHeight -= delta.y();
                
                parent->setMinimumHeight(parentHeight);
                parent->setMaximumHeight(parentHeight);
            }
        }
    };
    

    #include "gripLabel.h"
    QtWidgetsApplication8::QtWidgetsApplication8(QWidget* parent)
        : QMainWindow(parent)
    {
        ui.setupUi(this);
    
        QGridLayout* layout = new QGridLayout();
        ui.centralWidget->setLayout(layout);
    
    
        QFrame* frame = new QFrame(this);
        QGridLayout* frameLayout = new QGridLayout();
        frame->setLayout(frameLayout);
        frame->setObjectName("frame");
        frame->setStyleSheet("#frame { border: 4px solid red; }");
    
        frame->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
        frameLayout->setContentsMargins(0, 0, 0, 0);
    
        GripLabel* grip = new GripLabel(frame);
        frameLayout->addWidget(grip, 0, 1, 0, 1, Qt::AlignRight);
    
        layout->addWidget(frame, 0, 0);
    
    
        QFrame* frame2 = new QFrame(this);
        QGridLayout* frameLayout2 = new QGridLayout();
        frame2->setLayout(frameLayout2);
        frame2->setObjectName("frame2");
        frame2->setStyleSheet("#frame2 { border: 4px solid blue; }");
    
        frame2->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
        frameLayout2->setContentsMargins(0, 0, 0, 0);
    
        GripLabel* grip2 = new GripLabel(frame2);
        frameLayout2->addWidget(grip2, 0, 1, 0, 1, Qt::AlignRight);
    
        layout->addWidget(frame2, 1, 0);
    
    
        QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
        layout->addItem(spacer, 2, 0);
    
    
        layout->setRowStretch(0, 1);
        layout->setRowStretch(1, 1);
    }
    

    What I'm missing is find a way to get the widget resized by the GripLabel class be able to grow together her parent layout.

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by Chris Kawa
      #2

      The problem you have here is that you're trying to move part of a layout functionality into its contents. That leads to all sorts of problems, including the one you describe.

      A widget is not supposed to manage its own layout, because to do so it would have to have knowledge about its surroundings - the layout it is in, its siblings and parent. That's a lot of information not related to a function of a widget. Also what if you put your widget in a dock widget or fixed size container? It wouldn't behave properly.

      What you want to achieve here is basically a custom layout, not custom widget. A layout governs the geometry of its contents. It has access to all the widget's properties and sets their size/position. No trickery with min/max size is needed. Instead of subclassing a widget create your own subclass of QLayout. It could then resize all the widgets appropriately when parent is resized and you would avoid a lot of other problems. Widgets inside would not have to use min/max to define their geometry. They would just provide the usual size hints that the layout would respect You can achieve the drag resize behavior by installing an event filter in the layout when you add a widget to it. But it's the function of a layout, so it should be handled there, not in the widget.

      1 Reply Last reply
      1
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #3

        Hi,

        Beside the excellent points pointed by @Chris-Kawa, aren't you trying to recreate QSplitter ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        0

        • Login

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