Why drag and drop not working - qt

This is the basic example I found on qt doc. In tile Rectangle, i add anchors.fill: parent and commented all 3 lines below that because I feel like all those 3 line can be covered by anchors.fill: parent. But once I do that I cannot drag the element anymore.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
Item {
id: root
width: 64; height: 64
MouseArea {
id: mouseArea
anchors.fill: parent
anchors.centerIn: parent
drag.target: tile
onReleased: parent = tile.Drag.target !== null ? tile.Drag.target : root
Rectangle {
id: tile
anchors.fill: parent
// width: 64; height: 64
// anchors.verticalCenter: parent.verticalCenter
// anchors.horizontalCenter: parent.horizontalCenter
color: "red"
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: 32
Drag.hotSpot.y: 32
states: State {
when: mouseArea.drag.active
ParentChange { target: tile; parent: root }
AnchorChanges { target: tile; anchors.verticalCenter: undefined; anchors.horizontalCenter: undefined }
}
}
}
}
}
Why filling the rectangle of the parent disables the drag and drop functionality?

You anchor a boat so that it is fixed at something. If you want to move it, you will need to break the anchor or pull the thing you anchored it to, with you.
That is what an anchor is for - to fix the anchored object to some other object. If you want to have it movable, you can't anchor it.
You still have the dragged object the same size as your parent, by setting:
width: parent.width
height: parent.height
But though it is the same size, once you move it, it will obviously not fill the parent anymore.
Now you might say:
"But hey! They do anchor the object, too!"
Yes, they do, but there are also the lines:
states: State {
when: mouseArea.drag.active
ParentChange { target: tile; parent: root }
AnchorChanges { target: tile; anchors.verticalCenter: undefined; anchors.horizontalCenter: undefined }
}
which will lift the anchor when the tile is being dragged.

Related

Draggable item get hidden behind other UI elements - Qt Qml

In my application window I have two ItemPanels which is orgnized inside a RawLayout.
Item {
RowLayout {
anchors.fill: parent
spacing: 1
ItemPanel {
Layout.preferredWidth: 250
Layout.fillHeight: true
panelHeader: "Components"
DraggableItem {
width: 100; height: 100;
}
}
ItemPanel {
Layout.preferredWidth: 250
Layout.fillHeight: true
panelHeader: "Actions"
}
}
}
The Components panel contains DraggableItems. Droppable area is the Actions panel. But if I tried to drag an DraggableItem to the Actions panel, it will be hidden while I'm dragging it.
DraggableItem
Item {
id: root
property string colorKey: "red"
width: 64; height: 64
MouseArea {
id: mouseArea
width: 64; height: 64
anchors.centerIn: parent
drag.target: tile
onReleased: parent = tile.Drag.target !== null ? tile.Drag.target : root
Rectangle {
id: tile
width: 64; height: 64
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
color: colorKey
Drag.keys: [ colorKey ]
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: 32
Drag.hotSpot.y: 32
states: State {
when: mouseArea.drag.active
ParentChange { target: tile; parent: root }
AnchorChanges { target: tile; anchors.verticalCenter: undefined; anchors.horizontalCenter: undefined }
}
}
}
}
I was thinking adding a transparent layer and change the parent to it while dragging but I have no idea how to add a new layer on top of everything. Any other workarounds for this?
The easiest way would be to change the z-value of the ItemPanel with the panelHeader: "Components" to something greater than the siblings. Then automatically, all the children will be layered above them, too.
Reparenting is also a good solution. If you use ApplicationWindow as root object in your project, you don't even need to create add a new layer - it is already there.
You can use the attached property ApplicationWindow to reparent your draggable to ApplicationWindow.overlay. The only challange left is, that you need to specify the right position. You can use mapToItem() and mapFromItem() for this.
If you don't have ApplicationWindow as root, you can add a regualr Item as a child to your root and set the z-value to be the greates among its siblings. Then you assing it an id. If you don't shadow this id (having the same name for other identifiers, beeing resolved with higher priority) you can adress this Item from wherever. See more on this here.

Qt - change property from a component in a different qml file

Update 1
The idea is to be able to change the front and back of CardForm from main.qml because i want to be able to use multiple CardForm instances. I tried to do what they did here but it doesnt work.
Here is the code:
CardForm.qml
import QtQuick 2.0
Flipable {
id: sCard
width: 75
height: 200
property bool flipped: false
property string front: "Front"
property string back: "Back"
property alias callFront : front
property alias callBack : back
front: Rectangle{
id: front
anchors.fill: sCard
border.width: 2
border.color: "black"
radius: 5
Text{
anchors.centerIn: parent
text: sCard.front
}
}
back: Column{
Rectangle{
id: back
anchors.fill: sCard
radius: 5
border.width: 2
border.color: "black"
Text{
anchors.centerIn: parent
text: sCard.front
}
Text{
anchors.centerIn: parent
text: sCard.front
}
}
}
transform: Rotation{
id: flip
origin.x: sCard.width
origin.y: sCard.height/2
axis.x: 0; axis.y: 1; axis.z: 0 // set axis.y to 1 to rotate around y-axis
angle: 0 // the default angle
}
states: State {
name: "back"
PropertyChanges {
target: flip
angle: 180
}
when: sCard.flipped
}
transitions: Transition{
NumberAnimation {
target: flip
property: "angle"
duration: 200
}
}
MouseArea{
anchors.fill: parent
onClicked: sCard.flipped = !sCard.flipped
}
}
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Neuro Seed")
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
Column {
CardForm{
id: test
anchors.centerIn: parent
test.callFront: "Hello World!"
test.callBack: "Bonjour le Monde!
}
}
}
}
Here are the error messages:
SHGetSpecialFolderPath() failed for standard location "Shared Configuration", clsid=0x1c. ()
qrc:/main.qml:17:13: QML CardForm: back is a write-once property
qrc:/main.qml:17:13: QML CardForm: front is a write-once property
qrc:/main.qml:16:9: QML Column: Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column. Column will not function.
the c1.getFront() and getBack() were from a C++ class that I made. I changed these to "Hello World!" and "Bonjour le Monde!"
So after many hours of struggling I figured out that to create a property which is accessible by other .qml files you must create a property alias name: id.property. The id must point towards an existing instance of a object in your code and the property of this instance that you wish to be able to change from the outside. So in my case it would be like so:
CardForm.qml
Flipable {
id: sCard
width: 75
height: 200
property bool flipped: false
property alias frontText : front.text
front: Rectangle{
id: front
anchors.fill: sCard
border.width: 2
border.color: "black"
radius: 5
Text{
anchors.centerIn: parent
text: frontText
}
}
}
and in the main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Neuro Seed")
Rectangle {
anchors.fill: parent
CardForm{
id: test
anchors.centerIn: parent
frontText: "Hello World!"
}
}
}
}

Combine 2 MouseAreas on GridView

I have code like this:
GridView {
// ... declarations ...
model: theModel
delegate: MouseArea {
id: cellMouseArea
onClicked: // open the cell
}
MouseArea {
id: gridViewMouseArea
// here process horizontal mouse press/release actions
}
}
with a MouseArea defined in each delegate and an overall MouseArea covering my GridView. In the cellMouseArea I want to perform an open item action whereas in the gridViewMouseArea I want to implement mouseX handle to open/close a sidebar. However, the two MouseAreas do not work together. How can I carry it out?
You can exploit propagateComposedEvents:
If propagateComposedEvents is set to true, then composed events will
be automatically propagated to other MouseAreas in the same location
in the scene. Each event is propagated to the next enabled MouseArea
beneath it in the stacking order, propagating down this visual
hierarchy until a MouseArea accepts the event. Unlike pressed events,
composed events will not be automatically accepted if no handler is
present.
You can set the property to true on the GridView MouseArea. In this way click events are propagated to the MouseAreas in the delegates whereas the outer MouseArea can implement other behaviours such as drag or hoven.
Here is an example in which outer MouseArea defines drag property to slide in/out a Rectangle ( simulating your sidebar) and thanks to the propagateComposedEvents clicks are managed by the single delegates.
import QtQuick 2.4
import QtQuick.Window 2.2
ApplicationWindow {
width: 300; height: 400
color: "white"
Component {
id: appDelegate
Item {
width: 100; height: 100
Text {
anchors.centerIn: parent
text: index
}
MouseArea {
anchors.fill: parent
onClicked: {
parent.GridView.view.currentIndex = index
console.info("Index clicked: " + index)
}
}
}
}
Component {
id: appHighlight
Rectangle { width: 80; height: 80; color: "lightsteelblue" }
}
GridView {
anchors.fill: parent
cellWidth: 100; cellHeight: 100
highlight: appHighlight
focus: true
model: 12
delegate: appDelegate
MouseArea {
anchors.fill: parent
z:1
propagateComposedEvents: true // the key property!
drag.target: dragged
drag.axis: Drag.XAxis
drag.minimumX: - parent.width
drag.maximumX: parent.width / 2
onMouseXChanged: console.info(mouseX)
}
}
Rectangle{
id: dragged
width: parent.width
height: parent.height
color: "steelblue"
x: -parent.width
}
}

TextEdit line background color

Is it possible to set up background color for particular line of TextEdit (for instance when line is clicked)?
I will have TextEdit with width:500px and with 10 lines. I will click on line number 5, which is empty line, but i still want to change the background color of whole line. Is it possible?
I need to know if it is possible to develop fully customized code editor with Qt and Qml.
Here's a solution which relies on text edit's cursor rectangle:
FocusScope {
id: root
property alias font: textEdit.font
property alias text: textEdit.text
Rectangle {
color: "lightyellow"
height: textEdit.cursorRectangle.height
width: root.width
visible: root.focus
y: textEdit.cursorRectangle.y
}
TextEdit {
id: textEdit
anchors.fill: parent
focus: true
}
}
Original Answer:
Here's my proof of concept solution. It is a custom TextEdit component which highlights current line. It lacks proper line height calculation, but it can be either hard coded if only one font size is used or obtained from QFontMetrics.
import QtQuick 2.3
Item {
id: root
property alias font: textEdit.font
property alias text: textEdit.text
Column {
anchors.fill: parent
Repeater {
model: root.height / root.lineHeight
Rectangle {
color: index === textEdit.currentLine ? "lightyellow" : "transparent"
height: root.lineHeight
width: root.width
}
}
}
TextEdit {
id: textEdit
property int currentLine: text.substring(0, cursorPosition).split(/\r\n|\r|\n/).length - 1
// FIXME: Use proper line height (e.g. from QFontMetrics)
property int lineHeight: font.pixelSize + 2
anchors.fill: parent
}
}
If you want to highlight even empty lines, then you need to handle mouse clicks and keypad events and manually change colours of corresponding rectangles.
You can use cursorRectangle property of the TextEdit and FontMetrics for this purpose:
Item {
id: root
height: te.implicitHeight
FontMetrics {
id: fontMetrics
font: te.font
}
Rectangle {
x: 0; y: te.cursorRectangle.y
height: fontMetrics.height
width: te.width
color: "#e7e7e7"
visible: te.activeFocus
}
TextEdit {
id: te
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
}
}
You can see the result for my commercial project:

QML binding item issue

I have problem in binding item in QML, for example:
Rectangle{
id: thetarget
width:100
height:100
}
Item{
id: container
MouseArea{
id:mousearea
drag.target: thetarget //not work
anchors.fill: thetarget //not work
property int foo: thetarget.width //work
}
}
What I want is to make the bindings for drag.target, anchors.fill work without changing the structure (mousearea is not the sibling or child of thetarget). I have used Binding, function to return thetarget, but they are all useless. Could someone tell me what's wrong?
Set the parent of the mousearea to thetarget.
import QtQuick 1.1
Item {
Rectangle {
id: thetarget
width: 100
height: 100
}
Item {
id: container
MouseArea {
id: mousearea
parent: thetarget
drag.target: thetarget
anchors.fill: thetarget
property int foo: thetarget.width
}
}
}

Resources