在Qt Quick(QML)可轻拂中实现缩放/缩放的正确方法



我使用的是Qt 5.2 beta,Qt Quick 2.1。

我对Flickable组件有直接的问题。

这是最小的工作代码示例:

import QtQuick 2.1
import QtQuick.Controls 1.0
ApplicationWindow {
    width: 300
    height: 200
    Rectangle {
        anchors.fill: parent
        color: "green"
        Flickable {
            id: flickArea
            anchors {fill: parent; margins: 10; }
            contentWidth: rect.width;
            contentHeight: rect.height
            Rectangle {
                id: rect
                x: 0; y: 0;
                width: 200; height: 300;
                color: "lightgrey"
                Rectangle {
                    anchors { fill: parent; margins: 10; }
                    color: "red"
                }
            }
        }
    }
    Button {
        anchors.bottom: parent.bottom;
        anchors.horizontalCenter: parent.horizontalCenter;
        text: "Scale flickArea"
        onClicked: { flickArea.scale += 0.2; }
    }
}

当我进行缩放时,我希望所有子元素将像以前一样保持可见,并且内部区域会变大。

但相反,子元素会移出可轻拂内容。

有人可以提出一种避免此问题的正常方法,而无需手动重新计算所有偏移量吗?

我以这种方式按预期工作,但 IMO 这种方式有点棘手:

import QtQuick 2.1
import QtQuick.Controls 1.0
ApplicationWindow {
    width: 300
    height: 200
    Rectangle {
        anchors.fill: parent
        color: "green"
        Flickable {
            id: flickArea
            anchors {fill: parent; margins: 10; }
            contentWidth: rect.width*rect.scale
            contentHeight: rect.height*rect.scale
            Rectangle {
                id: rect
                transformOrigin: Item.TopLeft
                x: 0; y: 0;
                width: 200; height: 300;
                color: "lightgrey"
                Rectangle {
                    id: inner
                    anchors { fill: parent; margins: 10; }
                    color: "red"
                }
            }
        }
    }
    Button {
        anchors.bottom: parent.bottom;
        anchors.horizontalCenter: parent.horizontalCenter;
        text: "Scale flickArea"
        onClicked: {
            rect.scale += 0.2;
        }
    }
}

有人能提出更好的建议吗?

上。 我没有关闭这个问题 1 年,但仍然没有得到更好的解决方案或更好的做事方式。

使用缩放转换似乎是更好的解决方案:

import QtQml 2.11
import QtQuick 2.11
import QtQuick.Window 2.11
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.11
import QtQuick.Controls 2.4
import QtQuick.Controls.Material 2.4
import QtCharts 2.2
import QtGraphicalEffects 1.0
ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    property int scaleX: 1;
    Rectangle {
        anchors.fill: parent
        color: "green"
        Flickable {
            id: flickArea
            anchors {fill: parent; margins: 10; }
            contentWidth: rect.width*rect.scale
            contentHeight: rect.height*rect.scale
            transform: Scale { origin.x: 0; origin.y: 240; xScale: scaleX}
            Rectangle {
                id: rect
                transformOrigin: Item.TopLeft
                x: 0; y: 0;
                width: 200; height: 300;
                color: "lightgrey"
                Rectangle {
                    id: inner
                    anchors { fill: parent; margins: 10; }
                    color: "red"
                }
            }
        }
    }
    Button {
        anchors.bottom: parent.bottom;
        anchors.horizontalCenter: parent.horizontalCenter;
        text: "Scale flickArea"
        onClicked: {
//            flickArea.scale += 0.2;
            scaleX += 1;
            console.log(flickArea.contentWidth);
            console.log(flickArea.scale)
        }
    }
}

一种在qml中实现可缩放图像的传播方式

import QtQuick 2.15
Flickable
{
    id:flickable
    property int imageWidth
    property int imageHeight
    property alias source: mImage.source
    contentWidth: imageWidth
    contentHeight:imageHeight
    boundsBehavior: Flickable.StopAtBounds
    boundsMovement: Flickable.StopAtBounds

    states: [
        State {
            name: "state_StickToCenter" // state is used when content size is less than flickable size then content
            // center should stick to flickable center
            when : ( flickable.contentWidth < flickable.width || flickable.contentHeight< flickable.height )
            PropertyChanges {
                target: flickable.contentItem
                anchors.horizontalCenter:  width < flickable.width ? flickable.horizontalCenter : undefined
                anchors.verticalCenter:   height < flickable.height ? flickable.verticalCenter : undefined
            }
        }
    ]
    onStateChanged: { cancelFlick(); returnToBounds(); }

    Image
    {
        id:mImage
        width:flickable.contentWidth;
        height: flickable.contentHeight;
        source: flickable.imageSource
        fillMode: Image.PreserveAspectFit;
        Component.onCompleted:
        {
            imageWidth = mImage.paintedWidth;
            imageHeight = mImage.paintedHeight
        }
        autoTransform: true
        PinchArea
        {
            id:pinchArea
            anchors.fill: parent
            property bool zoomTriggeredFromPinchArea:false
            property point pinchCenter;

            onPinchStarted: zoomTriggeredFromPinchArea=true;
            onPinchUpdated:
            {
                var newZoomFactor = privateProperties.currentZoomFactor+ privateProperties.currentZoomFactor*(pinch.scale-1);
                pinchCenter =pinch.center;
                privateProperties.zoom(privateProperties.getBoundedScaleFactor(newZoomFactor))
            }
            onPinchFinished:
            {
                privateProperties.currentZoomFactor +=  privateProperties.currentZoomFactor*(pinch.scale-1);
                privateProperties.currentZoomFactor = privateProperties.getBoundedScaleFactor(privateProperties.currentZoomFactor);
                zoomTriggeredFromPinchArea=false;
            }
            MouseArea
            {
                id:mouseArea
                anchors.fill: parent
                propagateComposedEvents :true
                scrollGestureEnabled: false
                hoverEnabled: true
                onDoubleClicked:
                {
                    if(privateProperties.currentZoomFactor>1)resetScale();
                    else
                    {
                        var widthScale = (flickable.width+20)/mImage.width;
                        var heightScale = (flickable.height+20)/mImage.height;
                        var maxScale = Math.max(widthScale,heightScale);
                        if(maxScale>1)
                        {
                            privateProperties.pointOfDoubleClick = Qt.point(mouseX,mouseY);
                            privateProperties.useDoubleClickPoint = true;
                            privateProperties.currentZoomFactor = maxScale;
                        }
                    }
                }
                onWheel:
                {
                    if(wheel.modifiers===Qt.ControlModifier)
                    {
                        wheel.accepted=true;
                        var newZoomFactor;
                        if(wheel.angleDelta.y>0)
                            newZoomFactor = privateProperties.currentZoomFactor + (privateProperties.currentZoomFactor*privateProperties.zoomStepFactor);
                        else  newZoomFactor = privateProperties.currentZoomFactor - (privateProperties.currentZoomFactor*privateProperties.zoomStepFactor);
                        privateProperties.currentZoomFactor = privateProperties.getBoundedScaleFactor(newZoomFactor);
                        return;
                    }
                    wheel.accepted=false;
                }
            }
        }
    }
    QtObject
    {
        id : privateProperties
        property bool useDoubleClickPoint:false;
        property point pointOfDoubleClick;
        property real maxZoomFactor : 30.0
        property real zoomStepFactor :0.3;
        property real currentZoomFactor: 1
        property real minZoomFactor :1;
        property point scaleCenter : pinchArea.zoomTriggeredFromPinchArea
                                     ? pinchArea.pinchCenter : Qt.point(mouseArea.mouseX,mouseArea.mouseY);
        Behavior on currentZoomFactor {
            NumberAnimation { id:scaleNumberAnimation
                duration: pinchArea.zoomTriggeredFromPinchArea ? 0 : privateProperties.useDoubleClickPoint ?
                                                 Math.min(200*privateProperties.currentZoomFactor,500) : 200 ;
                onRunningChanged:  if(!running) privateProperties.useDoubleClickPoint=false;
            }
        }
        onCurrentZoomFactorChanged:
        {
            if(!pinchArea.zoomTriggeredFromPinchArea)
                zoom(currentZoomFactor);
        }
        function zoom(scaleFactor)
        {
            var targetWidth =  imageWidth*scaleFactor;
            var targetHeight  = imageHeight*scaleFactor;
            if(useDoubleClickPoint) resizeContent(targetWidth,targetHeight,mapToItem(mImage,pointOfDoubleClick));
            else resizeContent(targetWidth,targetHeight,scaleCenter);
            returnToBounds();
        }
        function getBoundedScaleFactor(ScaleFactor)
        {
            if(ScaleFactor>maxZoomFactor)ScaleFactor = maxZoomFactor;
            else if(ScaleFactor<minZoomFactor)ScaleFactor = minZoomFactor;
            return ScaleFactor;
        }
    }
    function resetScale()
    {
        privateProperties.pointOfDoubleClick = Qt.point(0,0);
        privateProperties.useDoubleClickPoint = true;
        privateProperties.currentZoomFactor = 1;
    }
}

相关内容

  • 没有找到相关文章

最新更新