Dragging from Listview to a droparea - qt

I am following this example here Using drag and drop with ListView to create an inventory UI. However, I have broken down the components into a main section, Listview and a droparea. Everything is working except, I cannot get the ReferenceError: listView is not defined. Please help
Main area
import QtQuick 2.15
import QtQuick.Controls 2.15
Page{
id:dragRect
Rectangle {
id: root
width: 400
height: 400
ListViewElem{
}
DropAreaElem{}
}
}
ListViewElem
import QtQuick 2.15
ListViewElem {
id: listView
width: parent.width / 2
height: parent.height
property int dragItemIndex: -1
model: ListModel {
Component.onCompleted: {
for (var i = 0; i < 10; ++i) {
append({value: i});
}
}
}
delegate: Item {
id: delegateItem
width: listView.width
height: 50
Rectangle {
id: dragRect2
width: listView.width
height: 50
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: "salmon"
border.color: Qt.darker(color)
Text {
anchors.centerIn: parent
text: modelData
}
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: dragRect2
drag.onActiveChanged: {
if (mouseArea.drag.active) {
listView.dragItemIndex = index;
}
dragRect2.Drag.drop();
}
}
states: [
State {
when: dragRect2.Drag.active
ParentChange {
target: dragRect2
parent: root
}
AnchorChanges {
target: dragRect2
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
]
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: dragRect2.width / 2
Drag.hotSpot.y: dragRect2.height / 2
}
}
}
DropAreaElem
import QtQuick 2.15
Rectangle {
width: parent.width / 2
height: parent.height
anchors.right: parent.right
color: "#aaff0011"
DropArea {
id: dropArea
anchors.fill: parent
onDropped: {
listView.model.remove(listView.dragItemIndex);
listView.dragItemIndex = -1;
}
}
}

You should provide id to your components
import QtQuick 2.15
import QtQuick.Controls 2.15
Page{
id:dragRect
Rectangle {
id: root
width: 400
height: 400
ListViewElem{
id: listView
}
DropAreaElem{
id: dropArea
}
}
}

Related

QML: how to add scrollbar into ListView

I have a simple ListView program and therein trying to attach scrollbar. There is no movement on list while scrolling up/ down, here, list should be moving accordingly. Seems, I am not able to set contentItem correctly. Looking for some hints.
Please find my sample core below, thereupon I added a vertical scrollbar to listView.rolesListModel is my model.
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
Window {
width: 400
height: 300
visible: true
ListModel
{
id:rolesListModel
ListElement
{
t:"One"
}
ListElement
{
t:"Two"
}
ListElement
{
t:"Three"
}
ListElement
{
t:"Five"
}
ListElement
{
t:"Six"
}
ListElement
{
t:"Seven"
}
ListElement
{
t:"Eight"
}
ListElement
{
t:"Nine"
}
ListElement
{
t:"Ten"
}
}
ListView {
id: listView
width: 150
height: 100
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
model: rolesListModel
clip: true
delegate: listRect
ScrollBar {
id: vbar
active: true
orientation: Qt.Vertical
size: listView.height / listView.contentHeight
position: listView.currentItem
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}
Component
{
id:listRect
Rectangle
{
id:listElementRect
height:20
width: 100
Text
{
id:elementText
width:parent.width
height:parent.height
text:t
horizontalAlignment: "AlignHCenter"
}
}
}
}
Newer way
You're using an older version of QML, QtQuick is now at 2.14. If you were okay moving from ScrollBar to a ScrollView, then the code for an arbitrary ListView would look like this:
import QtQuick 2.14
import QtQuick.Controls 2.14
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Scroll")
ScrollView {
anchors.fill: parent
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ListView {
width: parent.width
model: 20
delegate: ItemDelegate {
text: "Item " + (index + 1)
width: parent.width
}
}
}
}
Please note the essential scrollbar configuration line ScrollBar.vertical.policy: ScrollBar.AlwaysOn
https://doc.qt.io/qt-5/qml-qtquick-controls2-scrollview.html#scroll-bars
Older way
If, however, you would like to continue with your code, then the fix is to specifically declare that the vertical scrollbar property is bound to your scrollbar
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 2.0
Window {
width: 400
height: 300
visible: true
ListModel
{
id:rolesListModel
ListElement
{
t:"One"
}
ListElement
{
t:"Two"
}
ListElement
{
t:"Three"
}
ListElement
{
t:"Five"
}
ListElement
{
t:"Six"
}
ListElement
{
t:"Seven"
}
ListElement
{
t:"Eight"
}
ListElement
{
t:"Nine"
}
ListElement
{
t:"Ten"
}
}
ListView {
id: listView
width: 150
height: 100
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
model: rolesListModel
clip: true
delegate: listRect
ScrollBar.vertical: vbar
ScrollBar {
id: vbar
active: true
orientation: Qt.Vertical
size: listView.height / listView.contentHeight
position: listView.currentItem
policy: ScrollBar.AlwaysOn
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}
Component
{
id:listRect
Rectangle
{
id:listElementRect
height:20
width: 100
Text
{
id:elementText
width:parent.width
height:parent.height
text:t
horizontalAlignment: "AlignHCenter"
}
}
}
}
Please note the crucial ScrollBar.vertical: vbar line, which assigns your ScrollBar component vbar to the ListView.
https://doc.qt.io/qt-5/qml-qtquick-controls2-scrollbar.html#details

QML DelegateModel: Access DelegateModel from delegate

I'm trying to create a ListView with different delegates and a drag'n'drop functionality. The delegates shall be loaded with a Loader.
The QML Documentation provides a working example for a ListView without a Loader:
http://doc.qt.io/qt-5/qtquick-tutorials-dynamicview-dynamicview3-example.html
However, using the Loader I get the error: Cannot read property 'DelegateModel' of undefined
I do not understand how I can access the DelegateModel from the Loader.
A hint to the solution is highly appreciated!
main.qml:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Window 2.0
import QtQuick.Dialogs 1.1
import QtQml.Models 2.3
Window {
id: mainroot
visible: true
width: 640
height: 480
Rectangle{
id:viewContainer
anchors.fill: parent
DelegateModel {
id: visualModel
model: ListModel{
id:m_model
ListElement{
type:1
m_text :"Text1"
}
ListElement{
type:1
m_text :"Text2"
}
}
delegate: Loader{
id:idLoader
width: view.width
height: childrenRect.height
Component.onCompleted: {
switch(type){
case 1:
idLoader.setSource("TestDelegate.qml", {"m_text": m_text})
break;
}
}
}
}
ListView{
id: view
anchors.fill: parent
spacing: 5
model: visualModel
}
}
}
TestDelegate.qml:
import QtQuick 2.7
MouseArea {
id: dragArea
property bool held: false
property string m_text
anchors { left: parent.left; right: parent.right }
height: 50
width: view.width
drag.target: held ? content : undefined
drag.axis: Drag.YAxis
onPressAndHold: held = true
onReleased: held = false
Rectangle {
id: content
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
width: dragArea.width
height: textfield.implicitHeight
Drag.active: dragArea.held
Drag.source: dragArea
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
border.width: 1
border.color: "lightsteelblue"
color: dragArea.held ? "lightsteelblue" : "white"
Behavior on color { ColorAnimation { duration: 100 } }
radius: 2
states: State {
when: dragArea.held
ParentChange { target: content; parent: viewContainer }
AnchorChanges {
target: content
anchors { horizontalCenter: undefined; verticalCenter: undefined }
}
}
Text{
id: textfield
anchors.centerIn: parent
text: m_text
}
}
DropArea {
anchors { fill: parent; margins: 10 }
onEntered: {
visualModel.items.move(
idLoader.item.drag.source.DelegateModel.itemsIndex,
idLoader.item.dragArea.DelegateModel.itemsIndex)
}
}
}
The items defined in the file loaded with Loader or in general with any other .qml file that is imported should not depend directly on the main file since the ids have a scope, it is better to expose properties, in your case:
╭------------------------------------------╮
| bool held ------┿--->
| TestDelegate string m_text ------┿--->
| ============ DelegateModel md ------┿--->
| int index ------┿--->
╰------------------------------------------╯
Considering the above, the solution is the following:
main.qml
import QtQuick 2.7
import QtQuick.Window 2.0
import QtQml.Models 2.3
Window {
id: mainroot
visible: true
width: 640
height: 480
Rectangle{
id:viewContainer
anchors.fill: parent
DelegateModel {
id: visualModel
model: ListModel{
id:m_model
Component.onCompleted: {
for(var i=0; i< 40; i++){
m_model.append({"type": 1, "m_text": "Text" + i})
}
}
}
delegate:
Loader{
id: idLoader
width: view.width
height: childrenRect.height
property int index: DelegateModel.itemsIndex
onIndexChanged: if(status == Loader.Ready) idLoader.item.index = index
Component.onCompleted: {
switch(type){
case 1:
idLoader.setSource("TestDelegate.qml", {
"m_text": m_text,
"index": index,
"md": visualModel
})
break;
}
}
}
}
ListView{
id: view
anchors.fill: parent
spacing: 5
model: visualModel
}
}
}
TestDelegate.qml
import QtQuick 2.7
import QtQml.Models 2.3
MouseArea {
id: dragArea
property bool held: false
property string m_text
property DelegateModel md: null
property int index : -1;
anchors { left: parent.left; right: parent.right }
height: 50
width: view.width
drag.target: held ? content : undefined
drag.axis: Drag.YAxis
onPressAndHold: held = true
onReleased: held = false
Rectangle {
id: content
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
width: dragArea.width
height: textfield.implicitHeight
Drag.active: dragArea.held
Drag.source: dragArea
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
border.width: 1
border.color: "lightsteelblue"
color: dragArea.held ? "lightsteelblue" : "white"
Behavior on color { ColorAnimation { duration: 100 } }
radius: 2
states: State {
when: dragArea.held
ParentChange { target: content; parent: viewContainer }
AnchorChanges {
target: content
anchors { horizontalCenter: undefined; verticalCenter: undefined }
}
}
Text{
id: textfield
anchors.centerIn: parent
text: m_text
}
}
DropArea {
anchors { fill: parent; margins: 10 }
onEntered: {
if(md !== null)
md.items.move(drag.source.index, dragArea.index)
}
}
}

Drag and Drop in ListView

I am trying to drag and drop a ListView row and I am having trouble at the drag stage. Below code doesn't drag anything and name column is not aligned properly. I don't want to specify a size for ListView and I want it to get its size from its content Row with id row. It should be able to because text has size coming from its font size and Rectangle has set width. ListView can get wider as needed to show the name part.
import QtQuick 2.11
import QtQuick.Layouts 1.11
ListView {
id: root
height: scrollview.viewport.height
model: listModel
delegate: dragDelegate
Component {
id: dragDelegate
MouseArea {
id: dragArea
anchors { left: parent.left; right: parent.right }
height: content.height
drag.target: pressed ? content : undefined
drag.axis: Drag.XAndYAxis
Rectangle {
id: content
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
height: row.implicitHeight
border.width: 1
border.color: "lightsteelblue"
color: "green"
radius: 2
states: State {
when: dragArea.pressed
ParentChange { target: content; parent: root }
AnchorChanges {
target: content
anchors { horizontalCenter: undefined; verticalCenter: undefined }
}
}
Row {
id: row
Text {
text: name
font.pointSize: 15
}
Rectangle {
height: parent.height
width: 40
color: hexColor
}
}
}
}
}
ListModel {
id: listModel
ListElement {
name: "first-name"
hexColor: "red"
}
ListElement {
name: "second-name"
hexColor: "green"
}
}
}

Make child object be always on top

I was wondering either the following functionality is available in QML: I need for a child object (a text here) to always stay on top of other object, no matter the child/ parent connection. Here is a MWE:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle
{
id: rectMain;
anchors.centerIn: parent
width: parent.width
height: parent.height
color: "white"
Rectangle
{
id: rect1;
width: 200;
height: 200;
x: 100;
y: 100;
color: "red";
Text
{
id: theText;
text: qsTr("text");
anchors.centerIn: parent;
}
}
Rectangle
{
id: rect2;
width: 200;
height: 200;
x: 200;
y: 200;
color: "yellow";
}
}
}
It will show this window:
As you can see the "text" is covered with rec2, as it's a child of rect1, which was created prior to rect2. Is it possible for the text to be always on top of rect2 with current parent/ child connection?
This is the idea I expressed above. But I really can imagine for myself how that could be used. If you could define your real goals we will find another solution, of course.
import QtQuick 2.11
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
width: 400
height: 400
visible: true
title: "Example"
Item {
z: 1
Repeater {
id: rectGenerator
property bool loaded: false
Component.onCompleted: rectGenerator.loaded = true
model: 10
delegate: Rectangle {
width: 100
height: 100
color: Qt.rgba(Math.random(),Math.random(),Math.random(),0.8)
x: Math.round(Math.random() * 300)
y: Math.round(Math.random() * 300)
Drag.active: dragArea.drag.active
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
}
}
}
}
Loader {
z: 2
sourceComponent: Repeater {
model: rectGenerator.model
delegate: Text {
x: rectGenerator.itemAt(index).x
y: rectGenerator.itemAt(index).y
width: 100
height: 100
text: "item " + (index + 1)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
active: rectGenerator.loaded
}
}

How to integrate ListView with FolderListModel using QML?

I am developing a file browser interface using QML. However, I find I cannot click any folder and the list covered the top button. I don't know what I did wrongly.
I used ListView and FolderListModel during the development. And I intend to make the interface as below and works like a file browser
The expected interface:
Source Code:
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import QtQuick.Window 2.1
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.1
import Qt.labs.folderlistmodel 2.1
import QtMultimedia 5.0
import QtQuick.Controls.Styles 1.4
import Qt.labs.platform 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property int index: 0
property bool isActive: true
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
Page1 {
Rectangle {
id:root;
state:"hidden";
color: "#212126";
property string folderPathName: "file:///C:/";
property bool rootPath:false;
signal message(string msg);
property int lineHeight: 90;
signal selectedFolder(string folderPath);
Button{
id:topLine;
text: "...";
width: root.width;
height: root.lineHeight;
onClicked: {
if (folderModel.parentFolder != ""){
root.folderPathName = folderModel.parentFolder;
}
else{
root.state = "hidden";
}
}
}
ListView{
id:listFileView;
anchors{
bottom: rectangleButton.top;
bottomMargin: 4;
right: root.right;
rightMargin: 0;
left: root.left;
leftMargin: 0;
top: topLine.bottom;
topMargin: 0;
}
clip:true;
delegate:Button{
text: fileName;
height:root.lineHeight;
width:root.width;
onClicked: {
if(folderModel.isFolder(index)){
root.folderPathName = folderModel.get(index, "fileURL");
}
}
}
model: FolderListModel{
id:folderModel;
objectName: "folderModel";
showDirs: true;
showFiles: true;
showDirsFirst: true;
nameFilters: ["*.mp3", "*.flac"];
folder:root.folderPathName;
}
}
Rectangle {
id: rectangleButton;
height: 20;
color: "#212126";
anchors{
left: root.left;
leftMargin: 0;
right: root.right;
rightMargin: 0;
bottom: root.bottom;
bottomMargin: 0;
}
Rectangle{
id:rectWhiteLine;
anchors{
left:parent.left;
right: parent.right;
top:parent.top;
}
height: 2;
color:"white";
}
}
}
}
Page {
}
}
footer: TabBar {
id: tabBar
currentIndex: swipeView.currentIndex
TabButton {
text: qsTr("Main")
}
TabButton {
text: qsTr("View")
}
}
}
After changing anchors{ bottom: rectangleButton.top; bottomMargin: 4; right: root.right; rightMargin: 0; left: root.left; leftMargin: 0; top: topLine.bottom; topMargin: 0; } to width: 200; height: 600, the interface turns to be below:
The folders cannot be clicked and they are not correctly aligned.
Maybe this example would be of any use to you.
I have added "back" button that goes up one folder, and buttons that represent folders inside ListView are colored orange.
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import Qt.labs.folderlistmodel 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: mainRect
x: 20
y: 20
width: 300
height: 450
border.color: "black"
radius: 30
ListView {
y: 30
width: parent.width
height: parent.height - 60
clip: true
model: FolderListModel {
id: folderListModel
showDirsFirst: true
// nameFilters: ["*.mp3", "*.flac"]
}
delegate: Button {
width: parent.width
height: 50
text: fileName
onClicked: {
if (fileIsDir) {
folderListModel.folder = fileURL
}
}
background: Rectangle {
color: fileIsDir ? "orange" : "gray"
border.color: "black"
}
}
}
}
Button {
anchors.left: mainRect.right
anchors.leftMargin: 5
text: "back"
onClicked: folderListModel.folder = folderListModel.parentFolder
}
}
To get clickable top area with "..." I would add Text there and Mouse Area to handle clicks:
Text {
width: parent.width
height: 30
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "..."
MouseArea {
anchors.fill: parent
onClicked: folderListModel.folder = folderListModel.parentFolder
}
}
Add this code inside mainRect i.e. after line radius: 30.

Resources