I'm trying to make zoomable Item (Image or any other component) and make it for tablet. Currently, my code looks like this:
Rectangle {
id: root
anchors.fill: parent
color: mainWindow.toGradient
Flickable {
id: flick
anchors.fill: parent
contentWidth: width
contentHeight: height
boundsBehavior: Flickable.StopAtBounds
PinchArea {
id: pArea
width: Math.max(flick.contentWidth, flick.width)
height: Math.max(flick.contentHeight, flick.height)
property real initialWidth
property real initialHeight
onPinchStarted: {
initialWidth = flick.contentWidth
initialHeight = flick.contentHeight
}
onPinchUpdated: {
flick.contentX += pinch.previousCenter.x - pinch.center.x
flick.contentY += pinch.previousCenter.y - pinch.center.y
flick.resizeContent(initialWidth * pinch.scale, initialHeight * pinch.scale, pinch.center)
}
onPinchFinished: {
flick.returnToBounds()
}
Rectangle {
width: flick.contentWidth
height: flick.contentHeight
color: "black"
Image {
anchors.fill: parent
source: "qrc:/image.jpg"
}
MouseArea {
anchors.fill: parent
onDoubleClicked: {
flick.contentWidth = root.width
flick.contentHeight = root.height
}
}
}
}
}
}
It works good, but when it's over all screen, i can still zoom out (make it smaller, that parent).
How can I stop zooming out (and if possible zooming in too) at some point/scale?
Thank you for your help!
In the end, I entrily removed Flickable and scaled Item instead.
Rectangle {
id: root
anchors.fill: parent
color: "black"
Item {
id: photoFrame
width: root.width
height: root.height
Image {
id: image
anchors.fill: parent
source: "image.jpg"
}
PinchArea {
anchors.fill: parent
pinch.target: photoFrame
pinch.minimumRotation: 0 //Rotation (i guess we don't need to rotate it)
pinch.maximumRotation: 0
pinch.minimumScale: 1 //Minimum zoom for camera
pinch.maximumScale: 4 //Maximum zoom for camera
onPinchUpdated: { //Dont zoom behind border
if(photoFrame.x < dragArea.drag.minimumX)
photoFrame.x = dragArea.drag.minimumX
else if(photoFrame.x > dragArea.drag.maximumX)
photoFrame.x = dragArea.drag.maximumX
if(photoFrame.y < dragArea.drag.minimumY)
photoFrame.y = dragArea.drag.minimumY
else if(photoFrame.y > dragArea.drag.maximumY)
photoFrame.y = dragArea.drag.maximumY
}
MouseArea {
id: dragArea
hoverEnabled: true
anchors.fill: parent
drag.target: photoFrame
scrollGestureEnabled: false // 2-finger-flick gesture should pass through to the Flickable
drag.minimumX: (root.width - (photoFrame.width * photoFrame.scale))/2
drag.maximumX: -(root.width - (photoFrame.width * photoFrame.scale))/2
drag.minimumY: (root.height - (photoFrame.height * photoFrame.scale))/2
drag.maximumY: -(root.height - (photoFrame.height * photoFrame.scale))/2
onDoubleClicked: { //Reset size and location of camera
photoFrame.x = 0
photoFrame.y = 0
photoFrame.scale = 1
}
onWheel: {
var scaleBefore = photoFrame.scale
photoFrame.scale += photoFrame.scale * wheel.angleDelta.y / 120 / 10
if(photoFrame.scale < 1)
photoFrame.scale = 1
else if(photoFrame.scale > 4)
photoFrame.scale = 4
if(photoFrame.x < drag.minimumX)//Dont zoom behind border of image
photoFrame.x = drag.minimumX
else if(photoFrame.x > drag.maximumX)
photoFrame.x = drag.maximumX
if(photoFrame.y < drag.minimumY)
photoFrame.y = drag.minimumY
else if(photoFrame.y > drag.maximumY)
photoFrame.y = drag.maximumY
}
}
}
}
}
Related
I'm trying to make a mouse selection rectangle.
But Rectangle {} object can't have negative width & height values.
So it only selects left-to-right & top-to-bottom:
Rectangle {
id: selectorRectangle
x: 0
y: 0
width: 0
height: 0
color: "#8000abcd"
border.color: "#00fbfb"
}
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onPressed: {
selectorRectangle.x = mouse.x
selectorRectangle.y = mouse.y
}
onPositionChanged: {
selectorRectangle.width = mouse.x - selectorRectangle.x
selectorRectangle.height = mouse.y - selectorRectangle.y
}
}
How can I achieve it?
Thanks!
Here is my implementation. You just need to keep the pressed point in a property and calculate the x,y,width,height accordingly to keep width and height positive.
Rectangle {
id: selectorRectangle
x: 0
y: 0
width: 0
height: 0
color: "#8000abcd"
border.color: "#00fbfb"
}
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
property var lastPressPoint: Qt.point(0,0)
onPressed: {
lastPressPoint.x = mouse.x;
lastPressPoint.y = mouse.y;
}
onPositionChanged: {
selectorRectangle.x = Math.min(lastPressPoint.x , mouse.x)
selectorRectangle.y = Math.min(lastPressPoint.y , mouse.y)
selectorRectangle.width = Math.abs(lastPressPoint.x - mouse.x);
selectorRectangle.height = Math.abs(lastPressPoint.y - mouse.y);
}
onReleased: {
selectorRectangle.x = 0;
selectorRectangle.y = 0;
selectorRectangle.width = 0;
selectorRectangle.height = 0;
}
}
I have two images:
1. normal image
2. same image with the ability to zoom.
I have 4 draggable shapes (A,B,C,D) on second image (image with the ability to zoom).
I want to display position of mouse on normal image (with draw a shape (canvas3)) when the position of A/B/C/D shapes changed on the zoomed image.
I used the following code but it does not show correct position. In fact, I want user can see position of mouse.
property int xwheel: 0
property int ywheel: 0
property alias source :image.source
id:mywin
property int highestZ: 0
property real defaultSize: mywin.width
property real surfaceViewportRatio: 1.5
ScrollView {
anchors.fill: parent
flickableItem.interactive: true
frameVisible: true
highlightOnFocus: true
style: ScrollViewStyle {
transientScrollBars: true
.........
}
Flickable {
id: flick
anchors.fill: parent
contentWidth: parent.width
contentHeight: parent.height
Rectangle {
id: photoFrame
width: parent.width
height: parent.height
scale:defaultSize / parent.width
Behavior on scale { NumberAnimation { duration: 200 } }
Behavior on x { NumberAnimation { duration: 200 } }
Behavior on y { NumberAnimation { duration: 200 } }
smooth: true
antialiasing: true
Image {
id:image
anchors.fill: parent
fillMode: Image.PreserveAspectFit
smooth: true
}
PinchArea {
anchors.fill: parent
pinch.target: photoFrame
pinch.minimumRotation: -360
pinch.maximumRotation: 360
pinch.minimumScale: 0.1
pinch.maximumScale: 10
pinch.dragAxis: Pinch.XAndYAxis
property real zRestore: 0
onSmartZoom: {
.....
}
MouseArea {
id: dragArea
hoverEnabled: true
anchors.fill: parent
drag.target: photoFrame
scrollGestureEnabled: false
onPressed: {
photoFrame.z = ++mywin.highestZ;
}
onWheel: {
...
}
}
Point {
id: pointA
onDragged: {
xwheel=pointA.x;
ywheel=pointA.y;
canvas3.requestPaint()
}
}
//Point B
//Point D
//Pint C
}
}
}
Image {
id:mainimage
width: parent.width/4
height: parent.height/4
smooth: true
source: image.source
Canvas {
id: canvas3
width: parent.width
height: parent.height
onPaint: {
var context = getContext("2d");
// Make canvas all white
......
context.beginPath();
//Style
.......
context.moveTo(xwheel/4, ywheel/4);
context.arc(xwheel/4, ywheel/4, 5, 0, 2*Math.PI, true)
context.fill();
context.stroke();
}
}
}
I'm looking for a simple way to create a rectangle in a QQuickItem.
I want to resize, and drag the borders of this rectangle like this (found at resizable QRubberBand)
Has someone an idea?
There are probably several ways to achieve the desired result. Since I've considered the implementation of a similar Component for a cropping tool software of mine, I'm going to share a toy example which uses part of that code.
Differently from the rubber band in the example, my Rectangle is resizable only on a single axis at a time. I'm confident that you can build on that and customise the code to meet your needs.
The basic idea of the code is to exploit the drag property of MouseArea. It can be used to move around the Rectangle and, combined with MouseX and MouseY properties, resize it.
Dragging is active inside the Rectangle whereas resizing is active on the knobs set on the sides of the Rectangle (no mouse cursor change is set for the sake of brevity).
import QtQuick 2.4
import QtQuick.Controls 1.3
ApplicationWindow {
title: qsTr("Test Crop")
width: 640
height: 480
visible: true
property var selection: undefined
Image {
id: image1
anchors.fill: parent
source: "http://cdn.cutestpaw.com/wp-content/uploads/2013/01/l-Kitty-attack.jpg"
MouseArea {
anchors.fill: parent
onClicked: {
if(!selection)
selection = selectionComponent.createObject(parent, {"x": parent.width / 4, "y": parent.height / 4, "width": parent.width / 2, "height": parent.width / 2})
}
}
}
Component {
id: selectionComponent
Rectangle {
id: selComp
border {
width: 2
color: "steelblue"
}
color: "#354682B4"
property int rulersSize: 18
MouseArea { // drag mouse area
anchors.fill: parent
drag{
target: parent
minimumX: 0
minimumY: 0
maximumX: parent.parent.width - parent.width
maximumY: parent.parent.height - parent.height
smoothed: true
}
onDoubleClicked: {
parent.destroy() // destroy component
}
}
Rectangle {
width: rulersSize
height: rulersSize
radius: rulersSize
color: "steelblue"
anchors.horizontalCenter: parent.left
anchors.verticalCenter: parent.verticalCenter
MouseArea {
anchors.fill: parent
drag{ target: parent; axis: Drag.XAxis }
onMouseXChanged: {
if(drag.active){
selComp.width = selComp.width - mouseX
selComp.x = selComp.x + mouseX
if(selComp.width < 30)
selComp.width = 30
}
}
}
}
Rectangle {
width: rulersSize
height: rulersSize
radius: rulersSize
color: "steelblue"
anchors.horizontalCenter: parent.right
anchors.verticalCenter: parent.verticalCenter
MouseArea {
anchors.fill: parent
drag{ target: parent; axis: Drag.XAxis }
onMouseXChanged: {
if(drag.active){
selComp.width = selComp.width + mouseX
if(selComp.width < 50)
selComp.width = 50
}
}
}
}
Rectangle {
width: rulersSize
height: rulersSize
radius: rulersSize
x: parent.x / 2
y: 0
color: "steelblue"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.top
MouseArea {
anchors.fill: parent
drag{ target: parent; axis: Drag.YAxis }
onMouseYChanged: {
if(drag.active){
selComp.height = selComp.height - mouseY
selComp.y = selComp.y + mouseY
if(selComp.height < 50)
selComp.height = 50
}
}
}
}
Rectangle {
width: rulersSize
height: rulersSize
radius: rulersSize
x: parent.x / 2
y: parent.y
color: "steelblue"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.bottom
MouseArea {
anchors.fill: parent
drag{ target: parent; axis: Drag.YAxis }
onMouseYChanged: {
if(drag.active){
selComp.height = selComp.height + mouseY
if(selComp.height < 50)
selComp.height = 50
}
}
}
}
}
}
}
A screenshot of the example:
MouseArea {
id:roiRectArea
anchors.fill: parent
onPressed: {
pressX = mouse.x
pressY = mouse.y
}
onReleased: {
releaseX = mouse.x
releaseY = mouse.y
rectWidth = releaseX
widthRect = releaseX - pressX
rectHeight = releaseY
heightRect = releaseY - pressY
}
onPositionChanged: {
releaseX = mouse.x
releaseY = mouse.y
widthRect = releaseX - pressX
heightRect = releaseY - pressY
}
Rectangle {
id:rectRoi
antialiasing: true
opacity: 0.4
x: pressX
y: pressY
width: widthRect
height: heightRect
border {
width: 2
color: "blue"
}
color: "#00F0F8FF"
MouseArea {
anchors.fill: parent
drag{
target: rectRoi
minimumX: 0
minimumY: 0
maximumX: parent.parent.width - parent.width
maximumY: parent.parent.height - parent.height
smoothed: true
}
onDoubleClicked: {
parent.destroy()
}
}
Rectangle {
width: rulersSize
height: rulersSize
color: "white"
anchors.horizontalCenter: parent.left
anchors.verticalCenter: parent.top
id: selComp
MouseArea {
anchors.fill: parent
drag{ target: parent; axis: Drag.XAxis }
onMouseXChanged: {
if(drag.active){
var newWidth = rectRoi.width - mouseX
if (newWidth < 30)
return
rectRoi.width = newWidth
rectRoi.x = rectRoi.x + mouseX
}
}
drag{ target: parent; axis: Drag.YAxis }
onMouseYChanged: {
if(drag.active){
var newHeight = rectRoi.height - mouseY;
if (newHeight < 30)
return
rectRoi.height = newHeight
rectRoi.y = rectRoi.y + mouseY
}
}
}
}
Rectangle {
width: rulersSize
height: rulersSize
color: "red"
anchors.horizontalCenter: parent.left
anchors.verticalCenter: parent.bottom
MouseArea {
anchors.fill: parent
drag{ target: parent; axis: Drag.XAxis; }
onMouseXChanged: {
if(drag.active) {
var newWidth = rectRoi.width - mouseX
if (newWidth < 30)
return
rectRoi.width = newWidth
rectRoi.x = rectRoi.x + mouseX
}
}
drag{ target: parent; axis: Drag.YAxis }
onMouseYChanged: {
if(drag.active){
var newHeight = rectRoi.height + mouseY;
if (newHeight < 30)
return
rectRoi.height = newHeight
}
}
}
}
Rectangle {
width: rulersSize
height: rulersSize
color: "orange"
anchors.horizontalCenter: parent.right
anchors.verticalCenter: parent.bottom
MouseArea {
anchors.fill: parent
drag{ target: parent; axis: Drag.XAxis }
onMouseXChanged: {
if(drag.active){
var newWidth = rectRoi.width + mouseX
if (newWidth < 30)
return
rectRoi.width = newWidth
}
}
drag{ target: parent; axis: Drag.YAxis }
onMouseYChanged: {
if(drag.active){
var newHeight = rectRoi.height + mouseY;
if (newHeight < 30)
return
rectRoi.height = newHeight
}
}
}
}
Rectangle {
width: rulersSize
height: rulersSize
color: "green"
anchors.horizontalCenter: parent.right
anchors.verticalCenter: parent.top
MouseArea {
anchors.fill: parent
drag{ target: parent; axis: Drag.XAxis; }
onMouseXChanged: {
if(drag.active){
var newWidth = repeater.itemAt(index).width + mouseX
if (newWidth < 30)
return
repeater.itemAt(index).width = newWidth
}
}
drag{ target: parent; axis: Drag.YAxis }
onMouseYChanged: {
if(drag.active) {
var newHeight = repeater.itemAt(index).height - mouseY;
if (newHeight < 30)
return
repeater.itemAt(index).height = newHeight
repeater.itemAt(index).y = repeater.itemAt(index).y + mouseY
}
}
}
}
}
}
Hope it will help someone
How do you tell flickable to move to the bottom of the current page. QML - Move to top #TOP does not provide an answer for this.
You will need to calculate it and set it to contentY. For e.g:
Flickable {
width: 200; height: 200
contentWidth: image.width; contentHeight: image.height
Image { id: image; source: "file:///path/toBigImageFile" }
contentY : contentHeight-height
}
I kept adding text to a TextArea and wanted it to stay at the bottom unless someone changed the scroll position.
Flickable{
id: flickable
anchors.fill: parent
boundsBehavior: Flickable.DragAndOvershootBounds
flickableDirection: Flickable.VerticalFlick
ScrollBar.vertical: ScrollBar {
id: flickScroll
}
TextArea.flickable: TextArea{
id: monitor
width: parent.width
height: parent.height
readOnly: true
wrapMode: TextArea.Wrap
persistentSelection: true
leftPadding: 6
rightPadding: 6
topPadding: 0
bottomPadding: 0
background: null
}
function currPos(){
return flickable.contentY
}
function setPos(pos){
flickable.contentY = pos;
}
function getEndPos(){
var ratio = 1.0 - flickable.visibleArea.heightRatio;
var endPos = flickable.contentHeight * ratio;
return endPos;
}
function scrollToEnd(){
flickable.contentY = getEndPos();
}
function append(text){
var pos, endPos, value;
value = monitor.text + String(text);
// Limit value size here
endPos = getEndPos();
pos = currPos();
monitor.text = value;
if(pos == endPos){
scrollToEnd();
} else {
setPos(pos);
}
}
}
I am working on development of a UI where i am required to implement something similar effect of dragging the status bar in any smart phone.
This should slide the element downwards on click.(which means its height is increased)
I tried using the following code to take of " NO x,y values change " of the element
MouseArea{
id : zone2MouseArea
anchors.fill : parent
drag.target: zone2ID
drag.axis: Drag.YAxis
drag.minimumY: 0
drag.maximumY: 0.1
}
and onYChanged () i increased the height.
However this does not suffice my requirement. I need to slide the element changing its view interms of height without changing its x,y values
I have made a basic example. Hope it helps. I dont have an IDE with me as of now, so please check for syntax errors
import QtQuick 1.1
Rectangle
{
width: 560
height: 560
color: "blue"
Rectangle
{
id: slider
width: parent.width
height: parent.height
y: - parent.height * .90
color: "yellow"
property bool isAtTop: true
Behavior on y { NumberAnimation { duration: 300 } }
Text
{
text: qsTr("12:34 PM")
anchors.bottom: parent.bottom
color: "black"
}
Text
{
text: qsTr("Battery | Wifi | Updates")
anchors.centerIn: parent
color: "black"
font.pixelSize: 25
}
MouseArea
{
id: draggingMouse
anchors.fill : parent
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: - parent.height * .90
drag.maximumY: 0
onReleased:
{
if ( true == slider.isAtTop )
{
if( slider.y < - parent.height * .80 )
slider.y = - parent.height * .90
else
{
slider.y = 0
slider.isAtTop = false
}
}
else
{
if( slider.y < - parent.height * .20 )
{
slider.y = - parent.height * .90
slider.isAtTop = true
}
else
{
slider.y = 0
}
}
}
}
}
}