How to get it to work anchors animation, like described here:
import QtQuick 2.0
Item {
id: container
width: 200; height: 200
Rectangle {
id: myRect
width: 100; height: 100
color: "red"
}
Behavior on anchors.right {
AnchorAnimation { duration: 2000 }
}
Component.onCompleted: {
myRect.anchors.right = container.right
}
}
What am I doing wrong? There is no proper animation on changing anchors.
Also, if you can, provide some examples on this theme.
UPD: Provided simpler example.
AnchorAnimation can only be used in a Transition and in conjunction with an AnchorChange. It cannot be used in behaviors and other types of animations.
from AnchorAnimation documentation. There you can also find an example how to use states to do AnchorAnimations.
Related
I'm creating a "dotted paper" component for my QML app. Essentially this components consists of a dotted background that the user can zoom upon. To create this I used the following code:
DottedPaper.qml
import QtQuick 2.15
Rectangle{
id: page
property int spacing: 50
// this property changes the spacing between the dots
property real contentScale: 1.0
Repeater{
id: rowRepeater
model: 200
Repeater{
id: row
property int rowIndex: index
model: 200
Rectangle{
id: circle
color: "red"
width: 4; height: 4
x: index * spacing * page.contentScale + width/2;
y: rowIndex * spacing * page.contentScale+ height/2
radius: width/2
}
}
}
}
Then in my main file I have the following:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Flickable{
clip: true // doesn't improve anything
anchors.fill: parent
contentWidth: paper.width
contentHeight: paper.height
DottedPaper{
id: paper
width: 10000; height: 10000;
clip: true
}
}
// the slider changes the content scale of the dotted paper
Slider{
from: 1
to: 3
onValueChanged: paper.contentScale = value
}
}
The problem with this code is that it's slow. Upon checking the application does not render the content at 60fps, but I get around 45 - 50 fps on my desktop. I suspect the issues is that QML is reevaluating the contentScale property binding for each circle in the background even if the circle is not visible on the screen. What is the best way to prevent this?
It works a lot better if you change your Repeaters to be ListViews. That's because a ListView is smart enough to only create enough delegates as needed for the visible space. (At first I thought a GridView would work, but that doesn't give you enough control over rows/columns.)
Rectangle{
id: page
property int cellWidth: 50 * contentScale
property int dotWidth: 4
// this property changes the spacing between the dots
property real contentScale: 1.0
ListView {
id: grid
model: 200
anchors.fill: parent
anchors.leftMargin: page.dotWidth / 2
anchors.topMargin: page.dotWidth / 2
spacing: page.cellWidth - page.dotWidth
delegate: ListView {
model: 200
width: window.width
height: page.dotWidth
orientation: ListView.Horizontal
spacing: page.cellWidth - page.dotWidth
property int rowIndex: index
delegate: Rectangle{
id: circle
color: "red"
width: page.dotWidth; height: page.dotWidth
radius: width/2
}
}
}
}
I am trying to change the height of rows in my TreeView based on the item depth in the tree. The itemDelegate has access to the depth property (so I can change height of the item), but the row height can only be set from the rowDelegate, which can't see item depth.
As you can see from example I need to change row heights to match depth. How can the rowdelegate determine the item depth from the model?
Component {
id: delegateMenuItem
Column {
height: 100 // No effect
spacing: 20 // No effect
bottomPadding: 20 // No effect
Rectangle {
border {
color: "blue"
width: 2
}
color: "red"
height: itemText.height * 2
width: 300
Text {
id: itemText
text: qsTr(styleData.value)+"-"+height
color: "white"
font.pointSize: fontSize(styleData.depth)
}
}
}
}
Using TreeView from QQC1, I suggest that you try setting the implicitHeight for the itemDelegate and not setting any height for the rowDelegate. So try changing your snippet to:
itemDelegate: Rectangle {
id: delegateMenuItem
border { color: "blue"; width: 2 }
color: "red"
width: ...
implicitHeight: styleData.depth * ...
Text {
id: itemText
anchors.fill: parent
...
}
}
(In your current implementation delegateMenuItem does not have any implicitHeight. Meaning its height is probably 0. Also the ColumnLayout as you are using it is useless so I have removed it.)
I have not tried the above. However I have tried doing what you want to do with TreeView from Qt marketplace. It is designed to work with QQC2 and is based on TableView from QQC2 so you can use rowHeightProvider.
I need a reference to Cytoscape Canvas Object and it's 2D context. How can I do this? I don't see any "id" attribute on the canvas.
Thanks
You could acquire Cytoscape's canvas element and its context in the following way ...
var canvas = document.querySelector('canvas[data-id="layer2-node"]');
var context = canvas.getContext('2d');
Here's an example, showing how you could use the context to draw something on the canvas ...
var cy = cytoscape({
container: document.getElementById('cy'),
elements: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
{
data: {
id: 'ab',
source: 'a',
target: 'b'
}
}
]
});
var canvas = document.querySelector('canvas[data-id="layer2-node"]');
var context = canvas.getContext('2d');
// draw rectangle using general canvas method
function draw() {
context.fillRect(canvas.width / 2.1, 60, 30, 30);
requestAnimationFrame(draw);
}
draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.1.0/cytoscape.min.js"></script>
<div id="cy" style="width: 100%; height: 100%; position: absolute; top: 0px; left: 0px;"></div>
Following #maxkfranz's (Cytoscape dev) recommendations, I develop a lightweight Cytoscape.js extension called cytoscape-canvas that creates a canvas over and/or under a graph. It enables that full flexibility you're looking for.
If you're interested, check out the readme!
You shouldn't try to grab Cytoscape's canvas. Cytoscape uses several canvases for performance reasons, and you can't guarantee which type of context is valid. It may use context2d or it may use webgl for performance. Even if a context2d is uses, you can't keep track of when or what state changes (e.g. transforms) have happened on the canvas. And by making your own changes, you may break assumptions Cytoscape has made.
If you want overlay content, you should make your own overlay canvas. You generally shouldn't modify dom elements or js objects that belong to a lib outside of public/documented API.
What I am attempting to do is anchor an Item over a particular place over an Image. The Image needs to use Image.PreserveAspectFit for the fillMode. The problem I am having is that the height/width/paintedWidth/paintedHeight of the Image are for the entire image "canvas" (I'm not sure what it's actually called), not the drawn part of the image itself. So I can't anchor to the actual image.
See code below for an example I tried with anchors (red rectangle) and with a child rectangle and x,y coordinates (green rectangle).
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
visible: true
height: 400
width: 400
Image {
id: image
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: "image.jpg"
Rectangle {
id: bottomRight
width: 40
height: 40
color: "green"
x: parent.width * 0.75
y: parent.height * 0.75
}
}
Rectangle {
id: topLeft
width: 40
height: 40
color: "red"
anchors.top: image.top
anchors.left: image.left
anchors.topMargin: image.height * 0.25
anchors.leftMargin: image.width * 0.25
}
}
When you change the size of the window the placement of the rectangles is not in the same place over the image. I'd post some screenshots but I don't have enough reputation yet!
I poked around through the widget tree using the debugger but I can't seem to find any properties that provide the information about the scaling that I could use to calculate placement of the rectangles.
Update
I used the following functions to calculate the margins since I will be using potentially lots of these overlays.
function horMargin(val)
{
return ((image.width - image.paintedWidth)/2 + image.paintedWidth * val)
}
function verMargin(val)
{
return ((image.height - image.paintedHeight)/2 + image.paintedHeight * val)
}
Did you try to use paintedWidth and paintedHeight? :)
This will give you a rectangle that fills the painted image:
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
visible: true
height: 400
width: 400
Image {
id: image
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: "image.jpg"
}
Rectangle {
x: (image.width - image.paintedWidth) / 2
y: (image.height - image.paintedHeight) / 2
width: image.paintedWidth
height: image.paintedHeight
color: "transparent"
border.color: "darkorange"
border.width: 2
}
}
From there, you can work out how to apply the margins that you need.
I want to make a QML animation with QML Image element height property.
But negative value for Image height property does not work in Timer.
Can you tell me what is wrong with this animation?
import QtQuick 1.1
Rectangle {
width: 300
height: 300
property int mySize: 10
Image {
x: 150; y: 150
width: 20
height: -mySize // animation does not work in Timer, Why?
//height: mySize // animation works in Timer
source: "Bar.jpg"
}
Timer {
interval: 200
running: true
repeat: true
onTriggered: mySize +=5
}
}
First, (to answer your question), you can't use negative sizes. Use scaling instead, which supports negative values.
Scale {
yScale: ... // <-- change this value; 1 = original size
Image {
x: 150; y: 150
width: 20; height: 10 // <-- use constant size
source: "Bar.jpg"
}
}
Second, you clearly should read about animations in QML. In QML, you don't need timers to implement animations. The idea is that you only tell the start and end value of the property to be animated, and activate this animation. You can also configure the speed / duration of the animation and even the easing curve (to slow the animation down at the end and fancy stuff like bouncing...). One example could be:
import QtQuick 1.1
Rectangle {
width: 300; height:300
Scale {
Image {
x: 150; y: 150
width: 20; height: 10
source: "Bar.jpg"
}
NumberAnimation on yScale {
from: 1
to: -1
running: ... // <-- Animation is running while expression is true
}
}
}
Or, if you don't want to use an expression with property binding on Animation.running, you can also use the methods Animation.start(), stop(), etc. (Set an id on the animation to make it addressable from JavaScript.)
But understanding and working with property bindings in expressions is a major part of QML, so you should try to express what you want using expressions, not using method calls, events, conditions, whatever. That's the way QML is and why it is beautiful. ;)