c++qtqmlresizeqquickwidget

QQuickWidget Custom Resizing Mode


Note: This a self answered question. It cause me some headache to solve it in past, so I think it is worth to share.

I have a qml application designed for HD resolution(1366x768). It's using QtQuick.Layouts, so adaptable to custom resolution. But resizing it to less than HD resolution makes it squishy and meaningless. I am not restricting QQuickWidget's size with minimum size, cause now I'm trying to place multiple of them in grid layout of a QWidget. I want to scale down root item to fit in widget when size of QQuickWidget is less than initial size(1366x768). Problem is QQuickWidget offers only two ResizeMode options and none of them suits to my needs. And it is not possible deactiave ResizeMode. So I'm trying to disable ResizeMode and write a custom one.


Solution

  • It's kinda ugly but working solution. I checked the source code of QQuickWidget, and realized inner updateSize function does nothing when ResizeMode is invalid.

    CustomQuickWidget(QWidget* parent = nullptr)
        : QQuickWidget(parent) 
    {
        //set invalid resize mode for custom resizing
        setResizeMode(static_cast<QQuickWidget::ResizeMode>(-1));
        setSource(QML_SOURCE);
    }
    
    void CustomQuickWidget::resizeEvent(QResizeEvent *event) {
        QQuickWidget::resizeEvent(event);
    
        const int eventWidth = event->size().width();
        const int eventHeight = event->size().height();
        const int initialWidth = initialSize().width();
        const int initialHeight = initialSize().height();
    
        if (eventWidth >= initialWidth && eventHeight >= initialHeight) {
            // SizeRootObjectToView
            rootObject()->setSize(event->size());
            rootObject()->setScale(1);
        }
        else {
            // Scale down
            const qreal widthScale = qreal(eventWidth) / initialWidth;
            const qreal heightScale = qreal(eventHeight) / initialHeight;
    
            if (widthScale < heightScale) {
                // stretch height to fill
                rootObject()->setWidth(initialWidth);
                rootObject()->setHeight(qMin(int(eventHeight / widthScale), maximumHeight()));
                rootObject()->setScale(widthScale);
            }
            else {
                // stretch width to fill
                rootObject()->setWidth(qMin(int(eventWidth / heightScale), maximumWidth()));
                rootObject()->setHeight(initialHeight);
                rootObject()->setScale(heightScale);
            }
        }
    }
    
    QSize CustomQuickWidget::sizeHint() const { return initialSize(); }
    

    Make sure transformOrigin of root item is TopLeft.

    transformOrigin: Item.TopLeft