我正在尝试向我的图像添加缩放控件。我尝试从尽可能简单的开始,但我尝试的任何操作最终都会剪切图像。
图像已加载到屏幕的一部分中,我想将其放置在
Flickable
中,以便能够缩放和平移。稍后我将添加捏合和鼠标滚轮,现在我有按钮来设置各种比例值。
问题:缩放时,图像会移动并被剪切。这种转变很麻烦,因为缩放后的图像比容器大,为什么要显示空白空间?但剪辑更糟糕,我不明白。看起来偏移与剪辑一样大(也许?)。
我尝试改变
transformOrigin
,不好。我尝试使用 transform
而不是 scale
,但我没有看到任何反应。
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.0
import QtQuick.Window 2.2
Window {
width: 1015; height: 550; visible: true
Item { // A bunch of buttons to easily test several zoom values and layout is similar
id: leftSideContainer; width: 100; height: parent.height
ColumnLayout {
anchors.fill: parent; Layout.alignment: Qt.AlignCenter;
Layout.preferredHeight: 40; Layout.fillWidth: true;
Button { text: "50 %"; onClicked: imageContainer.imageScale = 0.5; }
Button { text: "80 %"; onClicked: imageContainer.imageScale = 0.8; }
Button { text: "100 %"; onClicked: imageContainer.imageScale = 1; }
Button { text: "110 %"; onClicked: imageContainer.imageScale = 1.1; }
Button { text: "120 %"; onClicked: imageContainer.imageScale = 1.2; }
Button { text: "150 %"; onClicked: imageContainer.imageScale = 1.5; }
Button { text: "200 %"; onClicked: imageContainer.imageScale = 2; }
Button { text: "400 %"; onClicked: imageContainer.imageScale = 4; }
Button { text: "landscape"; onClicked: { paintedCanvasImage.source = ""; paintedCanvasImage.source = "/examples/landscape.jpg"; } }
Button { text: "portrait"; onClicked: { paintedCanvasImage.source = ""; paintedCanvasImage.source = "/examples/portrait.jpg"; } }
Button { text: "square"; onClicked: { paintedCanvasImage.source = ""; paintedCanvasImage.source = "/examples/square.jpg"; } }
}
}
Item { // Using separate variable and item a bit like my code
id: imageContainer; property var imageScale: 1;
anchors { left: leftSideContainer.right; right: parent.right;
top: parent.top; bottom: parent.bottom; }
Rectangle { // Easy to show background compared to actual image, no other use
anchors.fill: parent; color: "lightgreen"; }
onImageScaleChanged: paintedCanvasImage.scale = imageScale;
Flickable { // I want to pan
id: flickImage
anchors.fill: parent
contentWidth: paintedCanvasImage.paintedWidth * paintedCanvasImage.scale
contentHeight: paintedCanvasImage.paintedHeight * paintedCanvasImage.scale
//contentX: ??? I have no idea
clip: true // required
boundsBehavior: Flickable.StopAtBounds
ScrollBar.vertical: ScrollBar { active: true; policy: ScrollBar.AsNeeded; }
ScrollBar.horizontal: ScrollBar { active: true; policy: ScrollBar.AsNeeded; }
Image {
id: paintedCanvasImage
width: imageContainer.width; height: imageContainer.height
source: "/examples/landscape.jpg" // Trying square, landscape or portrait
fillMode: Image.PreserveAspectFit // required
transformOrigin: Item.TopLeft // With this, weirdly the vertical fits correctly, horizontal only shifted/clipped
}
}
}
}
示例运行:我将在左上角和右下角显示 100 和 200%,以显示剪切和空白区域。请注意,使用
transformOrigin: Item.TopLeft
时,图像垂直放置(如果容器比图像更横向,否则水平放置) - 但向右移动了一些我不知道的量:
我不知道
transformOrigin
应该是什么,或者如何使用 transform
代替 scale
,或者 flickable 的起源必须是什么。 contentX
我以为可以修复它,但事实并非如此 - 必须需要一些有关转换的东西。
平台:windows以及嵌入式linux;
Qt版本:5.12
您的代码中有一些错误导致了该问题。 首先,裁剪问题是由于缺少
transformOrigin: Item.TopLeft
,这会导致默认情况下原点位于中心,并使图像的 x 和 y 比例为负值。paintedWidth
值引起的,根据 文档,该值可能小于图像项。fillMode: Image.PreserveAspectFit
,使用 container
总会导致图像周围出现空白区域。
对于解决方案,我做了一些更改,以便您可以轻松使用滚轮或捏合处理程序。
在下面的代码中,我添加了一个
fitSize
属性,它存储图像的初始大小,并且还使用图像的 sourceSize
计算长宽比。我还删除了图像的缩放部分以便能够使用flickable.resizeContent
。
通过将
fitSize
与 iscale
相乘,您可以获得新的尺寸。
这可能不是最佳实践,但效果很好,我认为您也可以使用
PinchHandler
代替 WheelHandler
。
Control {
id: container
property real iscale: 1
property size fitSize: {
const ss = image.sourceSize;
const ratio = ss.width / ss.height;
return ratio < 1 ? Qt.size(height * ratio, height) : Qt.size(width, width / ratio);
}
contentItem: Flickable {
id: flickable
clip: true
leftMargin: Math.max(0, width - contentWidth) / 2 // Centering the content
topMargin: Math.max(0, height - contentHeight) / 2
contentWidth: container.fitSize.width
contentHeight: container.fitSize.height
rebound: Transition {}
boundsBehavior: Flickable.StopAtBounds
ScrollBar.vertical: ScrollBar {}
ScrollBar.horizontal: ScrollBar {}
Image {
id: image
width: flickable.contentWidth
height: flickable.contentHeight
source: "win11.jpg"
onSourceChanged: container.iscale = 1
WheelHandler {
onWheel: function(e) {
const { width, height } = container.fitSize;
container.iscale += e.angleDelta.y / 1200;
flickable.resizeContent(width * container.iscale, height * container.iscale, point.position);
flickable.returnToBounds();
}
}
}
}
background: Rectangle { color: "#121314" }
}