how to use one model in two views - qml

i have one model for pictures and want to show them in grid view or list view (fullscreen) synchronously. if user clicks on one image in grid view i want this image to be shown in fullscreen mode (in listview).
i have one solution but my list view scrolls till "the current index".
THanx.
PhotoView.qml
Rectangle {
width: settings.pageWidth
height: settings.pageHeight
anchors.fill: parent
VisualDataModel {
id: visualModel
delegate: PhotoDelegate {}
model: photosModel
}
ListView {
id:fullscreen
anchors.fill: parent;
orientation: ListView.Horizontal
snapMode: ListView.SnapOneItem;
flickDeceleration: 500
//highlightFollowsCurrentItem: true
highlightRangeMode: ListView.StrictlyEnforceRange
preferredHighlightBegin: 0; preferredHighlightEnd: 0
cacheBuffer: width;
spacing: settings.largeMargin
model: visualModel.parts.grid
}
GridView{
id:grid
width: settings.pageWidth
height: settings.pageHeight
anchors.fill: parent
cellWidth: settings.gridCellWidth
cellHeight: settings.gridCellHeight
snapMode: GridView.SnapToRow
cacheBuffer: settings.pageHeight
clip: true
model: visualModel.parts.grid
}
// // Menu/Back Button
// IconButton{
// id: backButton
// iconSource: "qrc:///gfx/back_arrow.png"
// anchors.right: parent.right
// anchors.bottom: parent.bottom
// onClicked: mainWindow.close();
// }
// Fade Top
Image{
id:bottom_fade
source: "qrc:///gfx/bottom-page-fade.png"
height: 33
width: settings.pageWidth
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
// Fade Bottom
Image{
id:top_fade
source: "qrc:///gfx/top-page-fade.png"
height: 33
width: settings.pageWidth
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
}
}
PhotoDelegate.qml
import QtQuick 1.0
import Qt 4.7
import "../views"
import "../model"
import "../views/components"
Package {
Item { id: listDelegate; Package.name: 'list'; width: settings.pageWidth; height: settings.pageHeight }
Item { id: gridDelegate; Package.name: 'grid'; width: settings.pageWidth; height: settings.pageHeight }
Item {
id: wrapper
width: settings.pageWidth; height: settings.pageHeight
Image {
id: thumbnail; smooth: true; source: thumbnail_url
}
MouseArea {
anchors.fill: parent
onClicked: {
if (wrapper.state == 'inGrid') {
listDelegate.fullscreen.view.currentIndex = index;
wrapper.state = 'fullscreen'
} else {
gridDelegate.grid.view.currentIndex = index;
wrapper.state = 'inGrid'
}
}
}
state: 'inGrid'
states: [
State {
name: 'fullscreen'
ParentChange { target: wrapper; parent: listDelegate; x: 0; y: 0;
width: listDelegate.width; height: listDelegate.height
}
},
State {
name: 'inGrid'
ParentChange {
target: wrapper; parent: gridDelegate
x: 0; y: 0; width: gridDelegate.width; height: gridDelegate.height
}
}
]
transitions: [
Transition {
from: 'inGrid'; to: 'fullscreen'
SequentialAnimation {
PauseAnimation { duration: gridItem.GridView.isCurrentItem ? 0 : 600 }
ParentAnimation {
target: wrapper; via: foreground
NumberAnimation {
targets: [ wrapper]
properties: 'x,y,width,height,opacity'
duration: gridItem.GridView.isCurrentItem ? 600 : 1; easing.type: 'OutQuart'
}
}
}
},
Transition {
from: 'fullscreen'; to: 'inGrid'
ParentAnimation {
target: wrapper; via: foreground
NumberAnimation {
targets: [ wrapper ]
properties: 'x,y,width,height,opacity'
duration: gridItem.GridView.isCurrentItem ? 600 : 1; easing.type: 'OutQuart'
}
}
}
]
}
}

To showing selected item without scrolling until index of selected item is to synchronize the view elements current index:
onCurrentIndexChanged: {
your_component.positionViewAtIndex(currentIndex, YourViewElement.Contain)
}

Related

Columns of grouped checked boxes overlapping with one another

So, I'm trying to create a filter box for an ecommerce-based application that I'm working on and I want to make multiple button groups of check boxes within columns. I tried to separate the different columns but they overlap with one another. For example, the priceColumn overlaps with the conditionColumn. I am looking for a way to separate each button group by line. Is there anyway around this or any other solution that you would suggest? I'm new to QML by the way.
Here's my code for example:
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import "." as NeroshopComponents
Pane {
id: filterBox
clip: true // The area in which the contents of the filterBox will be bounded to (set width and height) // If clip is false then the contents will go beyond/outside of the filterBox's bounds
width: 250; height: 540
background: Rectangle {
color: (NeroshopComponents.Style.darkTheme) ? "#2e2e2e"/*"#121212"*/ : "#a0a0a0"
radius: 3
}
// conditionGroup
ButtonGroup {
id: conditionButtonGroup
buttons: conditionColumn.children
exclusive: false // more than one button in the group can be checked at any given time
checkState: conditionParentBox.checkState
onClicked: {
console.log("Selected condition:", button.text)
if(checkState == Qt.Unchecked) {
console.log("checkState: NO button is checked")
}
if(checkState == Qt.Checked) {
console.log("checkState: All buttons are checked")
}
if(checkState == Qt.PartiallyChecked) {
console.log("checkState: One or more buttons are checked")
}
}
}
// priceGroup
ButtonGroup {
id: priceButtonGroup
buttons: priceColumn.children
exclusive: false // more than one button in the group can be checked at any given time
checkState: priceParentBox.checkState
onClicked: {
console.log("Selected price range:", button.text)
if(checkState == Qt.Unchecked) {
console.log("checkState: NO button is checked")
}
if(checkState == Qt.Checked) {
console.log("checkState: All buttons are checked")
}
if(checkState == Qt.PartiallyChecked) {
console.log("checkState: One or more buttons are checked")
}
}
}
////////////////////
Rectangle {
id: filterOptions
//anchors.fill: parent
x: -horizontalScrollBar.position * width
y: -verticalScrollBar.position * height
color: "transparent"
width: parent.width
height: parent.height
Column {//ColumnLayout {
id: conditionColumn
Text {
text: qsTr("Condition");
font.bold: true
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
}
CheckBox {
id: conditionParentBox
//text: qsTr("Any")//qsTr("Parent")
checkState: conditionButtonGroup.checkState
Text {
text: qsTr("Any")
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
anchors.left: parent.right
anchors.leftMargin: 0
anchors.top: parent.top
anchors.topMargin: (parent.height - this.contentHeight) / 2
}
}
CheckBox {
//checked: false
//text: qsTr("New")
leftPadding: indicator.width
ButtonGroup.group: conditionButtonGroup
Text {
text: qsTr("New")
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
anchors.left: parent.right
anchors.leftMargin: 0
anchors.top: parent.top
anchors.topMargin: (parent.height - this.contentHeight) / 2
}
}
CheckBox {
//text: qsTr("Used")
leftPadding: indicator.width
ButtonGroup.group: conditionButtonGroup
Text {
text: qsTr("Used")
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
anchors.left: parent.right
anchors.leftMargin: 0
anchors.top: parent.top
anchors.topMargin: (parent.height - this.contentHeight) / 2
}
}
CheckBox {
//text: qsTr("Refurbished/Renewed")
leftPadding: indicator.width
ButtonGroup.group: conditionButtonGroup
Text {
text: qsTr("Refurbished/Renewed")
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
anchors.left: parent.right
anchors.leftMargin: 0
anchors.top: parent.top
anchors.topMargin: (parent.height - this.contentHeight) / 2
}
}
}
////////////////////////
Column {//ColumnLayout {
id: priceColumn
Text {
text: qsTr("Price")
font.bold: true
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
}
CheckBox {
id: priceParentBox
checkState: priceButtonGroup.checkState
Text {
text: qsTr("Any")
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
anchors.left: parent.right
anchors.leftMargin: 0
anchors.top: parent.top
anchors.topMargin: (parent.height - this.contentHeight) / 2
}
}
CheckBox {
leftPadding: indicator.width
ButtonGroup.group: priceButtonGroup
Text {
text: qsTr("$0.00-$1.00")
color: (NeroshopComponents.Style.darkTheme) ? "#ffffff" : "#000000"
anchors.left: parent.right
anchors.leftMargin: 0
anchors.top: parent.top
anchors.topMargin: (parent.height - this.contentHeight) / 2
}
}
}
} // Rectangle: filterOptions
ScrollBar {
id: verticalScrollBar
hoverEnabled: true
active: hovered || pressed
orientation: Qt.Vertical
size: (filterBox.height - 20) / filterOptions.height//filterBox.background.height / conditionColumn.height // 20 is the bottomMargin I guess?
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
policy: ScrollBar.AlwaysOn
}
ScrollBar {
id: horizontalScrollBar
hoverEnabled: true
active: hovered || pressed
orientation: Qt.Horizontal
size: filterBox.background.width / filterOptions.width
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
policy: ScrollBar.AsNeeded
}
// todo: sort by category, price, ratings, brand, color, etc.
}
I replaced your anchoring with ColumnLayout. I replaced Rectangle for Frame has an automatic border and padding effect. I replaced CheckBox for RadioButton, since, for exclusivity per group since your UI implied that use case. Qt QML automatically figures out how to deal with the two RadioButton groups since they fall in their own Frame/ColumnLayout so we needn't explicitly define a ButtonGroup. I replaced your ScrollBar implementation with ScrollBar.vertical
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
anchors.fill: parent
Flickable {
id: flickable
anchors.fill: parent
contentWidth: columnLayout.width
contentHeight: columnLayout.height
clip: true
ColumnLayout {
id: columnLayout
width: flickable.width - 20
Frame {
Layout.fillWidth: true
ColumnLayout {
width: parent.width
Label { text: qsTr("Condition") }
RadioButton { id: cond1; text: qsTr("Any") }
RadioButton { id: cond2; text: qsTr("New") }
RadioButton { id: cond3; text: qsTr("Used") }
RadioButton { id: cond4; text: qsTr("Refurbished/Renew") }
Text {
text: (cond1.checked && cond1.text)
|| (cond2.checked && cond2.text)
|| (cond3.checked && cond3.text)
|| (cond4.checked && cond4.text)
|| qsTr("Nothing Selected")
}
}
}
Frame {
Layout.fillWidth: true
ColumnLayout {
width: parent.width
Label { text: qsTr("Price") }
RadioButton { id: price1; text: qsTr("Any") }
RadioButton { id: price2; text: qsTr("$0.00-$1.00") }
Text {
text: (price1.checked && price1.text)
|| (price2.checked && price2.text)
|| qsTr("Nothing Selected")
}
}
}
}
ScrollBar.vertical: ScrollBar {
width: 20
policy: ScrollBar.AlwaysOn
}
}
}

GridLayout Arrangement

Following is my main.qml:
Window {
id: window
visible: true
width: 800
height: 480
title: qsTr("Hello World")
ListModel {
id: _listModel
ListElement {
textData: "E1"
isEnabled: false
}
ListElement {
textData: "E2"
isEnabled: false
}
ListElement {
textData: "E3"
isEnabled: false
}
ListElement {
textData: "E4"
isEnabled: false
}
ListElement {
textData: "E5"
isEnabled: false
}
ListElement {
textData: "E6"
isEnabled: false
}
}
ListView {
id: _listview
model: _listModel
width: 100
height: parent.height
anchors.right: parent.right
delegate: Item {
width: parent.width
height: 50
anchors.right: parent.right
Component.onCompleted:
{
if (isEnabled)
visibleRecs++;
}
RowLayout {
Text {
id: itemText
text: qsTr(textData)
}
CheckBox {
height: 30
width: height
checked: isEnabled
onCheckedChanged: {
isEnabled = checked
}
}
}
}
}
ScrollView {
id: _scrollView
width: parent.width / 2
height: parent.height
clip: true
GridLayout {
id: _gridLayout
anchors.fill: parent
anchors.horizontalCenter: parent.horizontalCenter
columnSpacing: 10
rowSpacing: 10
columns: 2
Repeater {
model: _listModel
Loader {
id: _loader
sourceComponent: isEnabled ? _recComponent : null
onLoaded: {
item.text = textData
}
}
}
}
}
Component {
id: _recComponent
Rectangle {
property alias text : _txt.text
id: _rec
width: 100
height: 50
radius: 5
color: "yellow"
Text {
id: _txt
anchors.centerIn: parent
}
}
}
}
The above code creates following (when all check boxes are ticked):
When all checkboxes are ticked:
When checkbox E3 is unchecked:
I want the items to be rearranged in the gridlayout if any of the item goes invisible.
E.g. in the above case when E3 is unchecked, I want my view to be something like this:
Please let me know, if it is possible to achieve. Thanks in advance.
The problem is that you still instantiate the Loader, you just set the sourceComponent to null. You have to make the item invisible to not use space in the GridLayout (or put width/height to 0)
ScrollView {
id: _scrollView
width: parent.width / 2
height: parent.height
clip: true
GridLayout {
id: _gridLayout
anchors.fill: parent
anchors.horizontalCenter: parent.horizontalCenter
columnSpacing: 10
rowSpacing: 10
columns: 2
Repeater {
model: _listModel
Loader {
id: _loader
visible: isEnabled
sourceComponent: isEnabled ? _recComponent : null
onLoaded: {
item.text = textData
}
}
}
}
}

QML Render the same Entity in two Scene3Ds

How can I insert the same entity to be displayed into more than one Scene3Ds in QML?
(it'll probably be abundantly clear that I'm pretty new to QML)
I would like to create something similar to the Multi Viewport QML Example, except I would like to have the viewports in differet layouts (e.g. a SplitView).
Ultimately I would like my entities (Mesh or SceneLoader entities) to be created completely outside of my views (my Scene3D), and be able to show the same data in multiple views without having copies.
I haven't had much luck putting a Layout into a Scene3D, and even so, that would constrain me against having the same data show up elsewhere. I simply can't figure out how to define my data outside the views, especially since I can't figure out how to append to the components/data/children properties.
For example, in the (long) example below, I figured out how to define torusMesh2 outside of the Scene3D by setting it's .parent to inject it into scene3DRightEntity, but I cannot figure out how to inject it into both Scene3Ds
import QtQuick 2.0
import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import QtQuick.Layouts 1.3
import QtQuick.Controls 1.3
import QtQuick.Scene3D 2.0
import Qt3D.Extras 2.0
Item {
Button {
text: 'Button'
onClicked: {
console.log('Button clicked');
}
}
SphereMesh {
id: torusMesh2; radius: 5
parent: scene3DRightEntity
}
PhongMaterial { id: material2; parent: scene3DRightEntity }
Transform { id: torusTransform2; scale3D: Qt.vector3d(1.5, 1, 0.5); rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45); parent: scene3DRightEntity }
Rectangle {
id: topRect
anchors.fill: parent; anchors.margins: 50
color: 'green'
SplitView {
anchors.fill: parent; orientation: Qt.Horizontal
Rectangle {
id: scene
anchors.margins: 50; width: 200; Layout.minimumWidth: 100; Layout.maximumWidth: 500
color: "darkRed"
Text { text: "View 1"; anchors.centerIn: parent }
Scene3D {
id: scene3dLeft
anchors.fill: parent; anchors.margins: 10; focus: true
aspects: ["input", "logic"]
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
Entity {
SimpleCamera {
id: camera1; fieldOfView: 45; position: Qt.vector3d( 0.0, 0.0, 40.0 )
}
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: camera1.camera
clearColor: "transparent"
}
}
, InputSettings { }
]
TorusMesh {
id: torusMesh1; radius: 5; minorRadius: 1; rings: 100; slices: 20
}
PhongMaterial { id: material1 }
Transform { id: torusTransform1; scale3D: Qt.vector3d(1.5, 1, 0.5); rotation: fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45) }
Entity {
id: torusEntity1
components: [ torusMesh1, material1, torusTransform1 ]
}
}
}
}
Rectangle {
id: scene2
Layout.fillWidth: true; Layout.minimumWidth: 50; Layout.maximumWidth: 400; height: 300
color: "darkBlue"
Scene3D {
id: scene3dRight
anchors.fill: parent; anchors.margins: 50; focus: true;
aspects: ["input", "logic"]
cameraAspectRatioMode: Scene3D.AutomaticAspectRatio
Entity {
id: scene3DRightEntity
SimpleCamera {
id: camera2
position: Qt.vector3d( 0.0, 0.0, 40.0 )
}
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: camera2.camera
clearColor: "transparent"
}
}
, InputSettings { }
]
Entity {
id: torusEntity2
components: [ torusMesh2, material2, torusTransform2 ]
}
}
}
}
}
}
} // Item
UPDATE
My first post was creating torusMesh2 as a child of the SplitView, this edit moves it to the top of the tree and sets its .parent.

QML listview Transition does not work for C++ Model

I have tried this example for add animation.It works
ListView {
width: 240; height: 320
model: ListModel {}
delegate: Rectangle {
width: 100; height: 30
border.width: 1
color: "lightsteelblue"
Text {
anchors.centerIn: parent
text: name
}
}
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 }
NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 }
}
displaced: Transition {
NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
}
focus: true
Keys.onSpacePressed: model.insert(0, { "name": "Item " + model.count })
}
When new record is inserted in model , add anim works perpeftly.But I want to refer model to C++ list like:
model:mymodel.list
When I add new record to list , listmodel is updated but add animation not take effect
I Find Solution by using QAbstractItemModel

Scale Element in StateELement

I can write lines below and got it work:
states: State {
name: "active"; when:myitem.activeFocus;
PropertyChanges { target: myitem; z:1000; scale: 1.2 }
}
transitions: Transition {
NumberAnimation { properties: scale; duration: 1000 }
}
But in these lines i can not give specific origin to scale property!
I found Scale Element
transform: Scale { origin.x: 25; origin.y: 25; xScale: 3}
How can i inject this into state property above, because i want to use "when" property of state,
i want scaling to run on that "when" condition.
Or is there any other way to scale in a condition with specifying origins?
Thanks for any idea.
You should set an id for the Scale element. Then you can change its properties in the "active" state.
Here a minimal working example:
import QtQuick 1.0
Item {
height: 200; width: 500
Rectangle {
id: myitem
height: 10; width: 100
anchors.centerIn: parent
color: "blue"
transform: Scale { id: scaleTransform; origin.x: 25; origin.y: 25 }
states: State {
name: "active"; when: mouseArea.pressed
PropertyChanges { target: scaleTransform; xScale: 3 }
}
transitions: Transition {
NumberAnimation { property: "xScale"; duration: 1000 }
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
}
}
Another possibility without states could be:
import QtQuick 1.0
Item {
height: 200; width: 500
Rectangle {
id: myitem
height: 10; width: 100
anchors.centerIn: parent
color: "blue"
transform: Scale {
id: scaleTransform
origin.x: 25; origin.y: 25
xScale: mouseArea.pressed ? 3 : 1 // <-
Behavior on xScale { // for animation
NumberAnimation { duration: 1000 }
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
}
}
xScale is set to 3 when mouse is pressed, else to 1 (if you don't know the " ternary operation" look here).