I've just started programming in QML and I need to make a simple Carousel with some images. I've found that the simplest way to do that is to use a PathView. According to that I've tried to make my current item on the center of the view,failing. Here's the code I've done.
Rectangle {
id: rectangle
height: 200
color: "#00000000"
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.fillWidth: true
PathView {
id: carouselView
anchors.fill: parent
model: listModel
delegate: Image {
width: PathView.isCurrentItem ? 256 : 128
height: PathView.isCurrentItem ? 256 : 128
source: iconSource
}
path: Path {
startX: 0
PathLine {
x: 800
y: 0
}
}
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
ListModel {
id: listModel
ListElement {
iconSource: "qrc:///images/chair.svg"
}
ListElement {
iconSource: "qrc:///images/chair.svg"
}
ListElement {
iconSource: "qrc:///images/chair.svg"
}
ListElement {
iconSource: "qrc:///images/chair.svg"
}
}
The desired effect is a simple horizontal carousel with a centered current item.
Current version used : 5.6
Here is a simple carousel example using PathView:
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
visible: true
width: 640
height: 640
Component {
id: delegate
Item {
width: 200; height: 200
scale: PathView.iconScale
opacity: PathView.iconOpacity
z: PathView.iconOrder
Image { anchors.fill: parent; source: modelData }
}
}
PathView {
id: view
anchors.fill: parent
anchors.bottomMargin: 150
anchors.topMargin: 50
pathItemCount: 7
preferredHighlightBegin: 0.5 //
preferredHighlightEnd: 0.5 // That should center the current item
highlightRangeMode: PathView.StrictlyEnforceRange //
model:
[
"http://placeimg.com/200/200/any?rand=" + Math.random(),
"http://placeimg.com/200/200/any?rand=" + Math.random(),
"http://placeimg.com/200/200/any?rand=" + Math.random(),
"http://placeimg.com/200/200/any?rand=" + Math.random(),
"http://placeimg.com/200/200/any?rand=" + Math.random(),
"http://placeimg.com/200/200/any?rand=" + Math.random(),
"http://placeimg.com/200/200/any?rand=" + Math.random(),
"http://placeimg.com/200/200/any?rand=" + Math.random(),
]
delegate: delegate
path: Path {
startX: 0; startY: view.height/2
PathAttribute { name: "iconScale"; value: 0.2 }
PathAttribute { name: "iconOpacity"; value: 10.2 }
PathAttribute { name: "iconOrder"; value: 0 }
PathLine {x: view.width / 2; y: view.height/2 }
PathAttribute { name: "iconScale"; value: 1.2 }
PathAttribute { name: "iconOpacity"; value: 1 }
PathAttribute { name: "iconOrder"; value: 8 }
PathLine {x: view.width; y: view.height/2 }
}
}
}
Sure, if you really want to place current item in the center of the view you just have to change the path, i.e. move start point to the center etc.
Related
I need to move an object by the clock and counterclockwise sequentially. But the for loop works differently, it only moves in the latter direction. When you click on the button, the object must first turn clockwise, and then counterclockwise. Maybe there is some kind of delay when performing the animation? How can I do it?
import QtQuick 2.15
import QtQuick.Window 2.14
import QtQuick3D 1.15
import QtQuick.Controls 2.14
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
visibility: "Maximized"
property int scl: 5
property int angle: 360
Node{
id: standAloneScene
DirectionalLight {
ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0)
}
Node {
id: sphere
Model {
id: model_sphere
source: "#Cube"
x: 200
y: 100
z: 0
materials: [
DefaultMaterial {
diffuseColor: Qt.rgba(0.053, 0.130, 0.219, 0.75)
}
]
}
}
ParallelAnimation{
id: start
running: false
NumberAnimation {
target: sphere
property: "eulerRotation.y"
to: angle
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: model_sphere
property: "eulerRotation.y"
to: 2*angle
duration: 2000
easing.type: Easing.InOutQuad
}
}
OrthographicCamera {
id: cameraOrthographicFront
eulerRotation.y: 45
eulerRotation.x: -45
x: 600
y: 800
z: 600
}
}
Rectangle {
id: view
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
height: parent.height
color: "#848895"
border.color: "black"
View3D {
id: topLeftView
anchors.fill: parent
importScene: standAloneScene
camera: cameraOrthographicFront
}
Button {
id: posmoveZ
width: view.width/8
height: view.height/16
anchors.top: view.top
anchors.right: view.right
text: "start"
font.pixelSize: height
onClicked: {
for(var i=0; i<6; i++){
if(i % 2 == 0){
angle = 360
}
else{
angle = -360
}
start.restart();
}
}
}
}
}
The simplest answer to your problem is put your animations inside a SequentialAnimation, i.e.
SequentialAnimation {
loops: 3
ParallelAnimation {
id: clockwise
NumberAnimation { /* ... */ }
NumberAnimation { /* ... */ }
}
ParallelAnimation {
id: counterClockwise
NumberAnimation { /* ... */ }
NumberAnimation { /* ... */ }
}
}
Also, you should let QML use the default width and height of a Button. Here's the complete solution:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import QtQuick3D 1.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
visibility: "Maximized"
property int scl: 5
property int angle: 360
Node{
id: standAloneScene
DirectionalLight {
ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0)
}
Node {
id: sphere
Model {
id: model_sphere
source: "#Cube"
x: 200
y: 100
z: 0
materials: [
DefaultMaterial {
diffuseColor: Qt.rgba(0.053, 0.130, 0.219, 0.75)
}
]
}
}
SequentialAnimation {
id: sequentialAnimation
loops: 3
ParallelAnimation{
id: clockwise
running: false
property int count: 3
NumberAnimation {
target: sphere
property: "eulerRotation.y"
from: 360
to: 0
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: model_sphere
property: "eulerRotation.y"
from: 720
to: 0
duration: 2000
easing.type: Easing.InOutQuad
}
}
ParallelAnimation{
id: counterClockwise
running: false
NumberAnimation {
target: sphere
property: "eulerRotation.y"
from: 0
to: 360
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: model_sphere
property: "eulerRotation.y"
from: 0
to: 720
duration: 2000
easing.type: Easing.InOutQuad
}
}
}
OrthographicCamera {
id: cameraOrthographicFront
eulerRotation.y: 45
eulerRotation.x: -45
x: 600
y: 800
z: 600
}
}
Rectangle {
id: view
anchors.top: parent.top
anchors.left: parent.left
width: parent.width
height: parent.height
color: "#848895"
border.color: "black"
View3D {
id: topLeftView
anchors.fill: parent
importScene: standAloneScene
camera: cameraOrthographicFront
}
Button {
id: posmoveZ
anchors.top: view.top
anchors.right: view.right
anchors.margins: 10
text: "start"
font.pixelSize: height
enabled: !clockwise.running && !counterClockwise.running
onClicked: {
sequentialAnimation.restart();
}
}
}
}
In QML How Can I create circular SwipeView?
Means If I am at last element, them next Item should be the first One.
SwipeView {
id: view
spacing: 20
currentIndex: 0
clip: true
anchors.fill: parent
}
Or Can I use tumbler which can contain different Items?
I am using this code
PathView {
id: view
anchors.fill: parent
snapMode:PathView.NoSnap
property int widthAllList: (widthItemNotSelect*3)+60
property int widthItemNotSelect: parent.width-13
anchors.horizontalCenter: parent.horizontalCenter
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
model: ["qrc:/QML/Widget/AnalogClock.qml",
"qrc:/QML/Widget/Clock.qml"
,"qrc:/QML/Widget/Widget.qml"]
delegate: Loader {
width: parent.width
height: parent.height
source: modelData
}
path: Path {
id:myPath
startX: 0
startY: parent.height/2
PathLine { x:view.widthAllList; y:parent.height/2 }
}
}
The simple example using PathView:
PathView {
id: view
anchors.fill: parent
snapMode: PathView.SnapToItem
model: ["Test1.qml","Test2.qml","Test3.qml"]
delegate: Loader {
width: parent.width
height: parent.height
source: modelData
}
path: Path {
startX: view.width/2; startY: view.height/2
PathQuad { x: view.width/2; y: -view.height*view.model.length; controlX: -view.width; controlY: view.height/2 }
PathQuad { x: view.width/2; y: view.height/2; controlX: view.width * view.model.length; controlY: view.height/2 }
}
}
The path in example above is for fun and example only, you can modify it as you want.
Example of item - Test1.qml:
import QtQuick 2.9
Rectangle{
color: "green"
width: parent.width
height: parent.height
Text {
anchors.centerIn: parent
text: "page " + index
}
}
The same trick could be done using Tumbler, I guess.
I have a QML Map widget. I want to drop some objects on it to get the latitude and longitude of the dropping point. How can I do it?
You can do that exactly as all other drag-n-drop applications. There are tons of examples as in Qt documentation as over the Internet.
One of them:
import QtQuick 2.9
import QtQuick.Window 2.0
import QtLocation 5.3
Window {
id: window
width: 600
height: 400
visible: true
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: item
propagateComposedEvents: true
onReleased: item.Drag.drop()
}
Plugin {
id: mapPlugin
preferred: ["osm", "esri"]
}
Map {
id: map
anchors.fill: parent
anchors.topMargin: 40
anchors.bottomMargin: 30
plugin: mapPlugin
center {
latitude: 40.785091
longitude: -73.968285
}
zoomLevel: 14
DropArea {
anchors.fill: parent
onDropped: {
var coord = map.toCoordinate(Qt.point(drop.x, drop.y));
output.text = "latitude:" + coord.latitude + ", longitude:" + coord.longitude;
anim.running = true;
}
}
}
Rectangle {
id: item
x: parent.width/2 - 20
y: 0
width: 40
height: 40
radius: 20
color: "orange"
opacity: 1
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: 20
Drag.hotSpot.y: 20
Text {
anchors.centerIn: parent
text: "Drop me"
font.pixelSize: 8
}
SequentialAnimation {
id: anim
running: false
NumberAnimation { target: item; property: "opacity"; to: 0; duration: 500 }
PropertyAction { target: item; property: "x"; value: window.width/2 - 20 }
PropertyAction { target: item; property: "y"; value: 0 }
NumberAnimation { target: item; property: "opacity"; to: 1; duration: 500 }
}
}
Text {
id: output
anchors.bottom: parent.bottom
height: 30
width: window.width
text: ""
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
I am trying to create a smoothly changing list in QML, but the animations have an unexpected side effect. This is my toy code that moves around items every time the window is resized:
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
visible: true
ListView {
id: listView1
x: 0
y: 0
width: parent.width
height: parent.height
onWidthChanged: {
model.move(0,1,2);
}
move: Transition {
SmoothedAnimation {
properties: "x,y"
duration: 1000
}
}
displaced: Transition {
SmoothedAnimation {
properties: "x,y"
duration: 1000
}
}
delegate: Item {
x: 5
onXChanged: {
console.log("x: ", x)
}
width: parent.width
height: 40
Text {
text: name
anchors.verticalCenter: parent.verticalCenter
font.bold: true
}
}
model: ListModel {
ListElement {
name: "Grey"
}
ListElement {
name: "Red"
}
ListElement {
name: "Blue"
}
}
}
}
Oddly enough, this is the output when I play around with that window:
QML debugging is enabled. Only use this in a safe environment.
qml: x: 0.7840000000000007
qml: x: 0
qml: x: 1.2960000000000003
qml: x: 0
qml: x: 1.2960000000000003
qml: x: 0
And it is not just temporary, some items change their x position permanently. Is this my fault?
I am trying to make an app which shows 3 pages at a time. The central page shows 3 rectangles displying sql query results 1-3 , the left page is a link to an image from query result 4, and the right page is also built from the same query and has a different layout. Now I am unable to fit these 3 pages into a listmodel and use pathview to make it look like a paginator, because all 3 pages are incongruent and not really a model, hence giving me error ListElement: cannot contain nested elements. I am pasting the code below. All i want is for the user to be able to flick between the pages, whether that involves a pathview or statechange with a decent transition to mimick flipping pages :
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0
import "content"
Rectangle{
property ListModel mainModel
id: tripleView
visible: true
width: 800
height: 1400
PathView {
model: mainModel
delegate: mainDelegate
id: paginator
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
anchors.fill: parent
path: Path {
startX: -tripleView.width * mainModel.count / 2 + tripleView.width / 2;
startY: tripleView.height / 2
PathLine {
x: tripleView.width * mainModel.count /2 + tripleView.width / 2
y: tripleView.height * .5 }
}
}
Component {
id: mainDelegate
Rectangle {
width: tripleView.width
height: tripleView.height
}
}
ListModel {
id: regionsModel
ListElement {
name: "Stomach"
}
ListElement {
name: "Lung"
}
ListElement {
name: "Colorectal"
}
ListElement {
name: "Pancreas"
}
ListElement {
name: "Urinary Bladder"
}
}
ListModel {
id: mainModel
ListElement{
Rectangle{
id: tnmPage
width: parent.width
height: container.height
Rectangle {
id: menu
z: 2
width: parent.width ;
height: 75
Component {
id: appDelegate
Rectangle {
width: genericText.width + 10; height: parent.height
id: wrapper
color: PathView.isCurrentItem ? "yellow" : "white"
Text {
id: genericText
height: parent.height
font.pointSize: 12
verticalAlignment: Text.AlignVCenter
// anchors.topMargin: wrapper.top
color: wrapper.PathView.isCurrentItem ? "red" : "black"
text: name
}
MouseArea {
// width:parent.width; height: parent.height
anchors.fill: parent
hoverEnabled: true
onClicked: {
var List = mWindow.printi(name)
t.content = List[1]
node.content = List[2]
mets.content = List[3]
view.currentIndex = index
}
}
}
}
PathView {
id: view
width: 2500
height: parent.height
anchors.rightMargin: 18
anchors.bottomMargin: 0
anchors.leftMargin: -18
anchors.topMargin: 0
anchors.fill: parent
// anchors.bottom: parent.bottom
// anchors.top: parent.top
// preferredHighlightBegin: .1
// preferredHighlightEnd: .6
highlightRangeMode: PathView.StrictlyEnforceRange
// anchors.rightMargin: 0
// anchors.bottomMargin: 0
// anchors.leftMargin: 2
// anchors.topMargin: -71
z: 1
highlight: Component {
Rectangle {
color: "yellow"
visible: PathView.onPath
}
}
focus: true
model: regionsModel
delegate: appDelegate
path: Path {
startX: 0; startY: view.height *.5
PathLine { x: menu.width; y: view.height * .5 }
}
}
}
Flickable {
id: flick
anchors.topMargin: menu.bottom
width: parent. width
height: parent. height - menu.height
contentWidth: parent.width+200
contentHeight: container.height // this is calculated on amount of text
PinchArea {
width: Math.max(flick.contentWidth, flick.width)
height: Math.max(flick.height, flick.height)
pinch.minimumScale: 0.5
pinch.maximumScale: 3
property real initialWidth
property real initialHeight
x: 0
y: 0
//![0]
onPinchStarted: {
initialWidth = flick.contentWidth
initialHeight = flick.contentHeight
flick.interactive = false
}
onPinchUpdated: {
t.fontSize = t.size*pinch.scale
node.fontSize = node.size * pinch.scale
mets.fontSize = mets.size * pinch.scale
}
onPinchFinished: {
flick.returnToBounds()
flick.interactive = true
}
Rectangle {
id: container
MouseArea {
anchors.fill: parent
onDoubleClicked: {
t.fontSize = 12
node.fontSize = t.size
mets.fontSize = t.size
}
}
anchors.top: flick.top
width: parent.width
height: t.height + node.height + mets.height
StageBox {
id: t
anchors.top: container.top
color: "#6acbd3"
}
StageBox {
id: node
anchors.top: t.bottom
color: "#1fd77b"
}
StageBox {
id: mets
anchors.top: node.bottom
color: "blue"
}
}
}
}
}
}
I realise the code above is lengthy, but i think it will give some idea about what i am trying to achieve. The examples i have found so far have simple pages displaying images and no nesting. Thank you for your help.
Try QML type VisualItemModel http://qt-project.org/doc/qt-4.8/qml-visualitemmodel.html#details .good luck
I have managed a hack. Experimentally implemented in colored rectangles, this flickable behaves as a 3-page app starting at mid page and allowing flicking horizontally to access neighbouring pages. It works and I am sure with some tweaking it can suit similar applications as mine. Comments invited
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0
Rectangle {
state: "baseState"
id: mainScreen
width: 400
height: 600
Text {
z:2
id: logTxt
height: 10
width: 20
function log(txt){
text = txt+"\n"
}
}
Flickable {
boundsBehavior: StopAtBounds
id: flick
y: 48
onContentXChanged: {
if(flick.contentX>100 && mainScreen.state=="baseState" && flick.flickingHorizontally){
logTxt.log(flick.contentX)
mainScreen.state="State1"
}
if(flick.contentX<-100 && mainScreen.state=="baseState" && flick.flickingHorizontally){
mainScreen.state="State2"
logTxt.log(flick.contentX)
}
if(flick.contentX>100 && mainScreen.state=="State2" && flick.flickingHorizontally ){
mainScreen.state="baseState"
logTxt.log(flick.contentX)
flick.contentX=0
}
if(flick.contentX<-100 && mainScreen.state=="State1" && flick.flickingHorizontally){
logTxt.log(flick.contentX)
mainScreen.state="baseState"
flick.contentX=0
logTxt.log(flick.contentX)
Timer
}
}
interactive: true
width: 400
height: 600
transformOrigin: Item.Center
flickableDirection: Flickable.HorizontalFlick
Rectangle {
width: 600
height: 600
id: container
Rectangle {
id:two
visible: false
x: 0
z:3
height: 600
width: 400
color: "grey"
}
Row{
id: testGrid
x:0
visible: true
y: 0
z: 3
width:600
height: 600
Rectangle {
id: a
anchors.top:parent.top
color:"#f6f7b1"
visible: true
z: 3
height: parent.height
width: 200
}
Rectangle {
id: b
anchors.top:parent.top
color:"#ffebeb"
visible: true
height: parent.height
width: 200
}
Rectangle {
id: c
y: -35
anchors.top:parent.top
color:"#b1d5f7"
height: parent.height
width: 200
}
}
Rectangle {
id: three
visible: false
z:2
x:0
height: parent.height
width: 400
color: "#028000"
}
}
}
states: [
State {
name: "State1"
PropertyChanges {
target: testGrid
visible: false
}
PropertyChanges {
target: two
visible: true
}
PropertyChanges {
target: three
visible: false
}
},
State {
name: "State2"
PropertyChanges {
target: testGrid
visible: false
}
PropertyChanges {
target: three
visible: true
}
PropertyChanges {
target: two
visible: false
}
},
State {
name: "baseState"
PropertyChanges {
target: testGrid
visible: true
}
PropertyChanges {
target: three
visible: false
}
PropertyChanges {
target: two
visible: false
}
}
]
}