How to make TableView Items draggable - qml

I’ve a TableView and have implemented my own item delegate for it. I want to be able to drag it out and place it somewhere else. How do I do it
itemDelegate: Text {
id: objMainText
anchors.horizontalCenter: parent.horizontalCenter
elide: styleData.elideMode
color: "yellow"
text: styleData.value.get(0).content //assume this is correct
MouseArea {
id: objDragArea
anchors.fill: parent
drag.target: objDragableText
drag.axis: Drag.XAndYAxis
hoverEnabled: true
onEntered: {
console.log("Hover Captured") //This gets printed
}
onClicked: {
console.log("Detected") //This NEVER gets printed
}
Text {
id: objDragableText
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Drag.active: objDragArea.drag.active
opacity: Drag.active / 2
text: objMainText.text
color: objMainText.color
states: State {
when: { objDragArea.drag.active }
AnchorChanges {
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
}
}
}
Don’t mind if there are a few brackets less here and there. Those I’m taking care of ofcourse. But why can’t I drag objDragableText and how do i do it?
Also, onClicked is captured as in the comments above but not onPressed. How do I also do this?
{Qt 5.1 RC 1 - Win7 - MinGw 4.8}

Related

Qt6 QML QQmlApplicationEngine failed to load component error

I want to use component in QtQuick, i have two qml files one is main.qml and the second button.qml, and iam using this example for their documentation, but when i run my code it is giving me error that QQmlApplicationEngine failed to load component
qrc:/bbb/main.qml:13:5: Button is not a type. also iam seeing some red error in the imported Button in main.qml.
main.qml
import QtQuick
Window {
id:root
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Button { // our Button component
id: button
x: 12; y: 12
text: "Start"
onClicked: {
status.text = "Button clicked!"
}
}
Text { // text changes when button was clicked
id: status
x: 12; y: 76
width: 116; height: 26
text: "waiting ..."
horizontalAlignment: Text.AlignHCenter
}
}
Button.qml
import QtQuick 2.0
Item {
Rectangle {
id: root
// export button properties
property alias text: label.text
signal clicked
width: 116; height: 26
color: "lightsteelblue"
border.color: "slategrey"
Text {
id: label
anchors.centerIn: parent
text: "Start"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.clicked()
}
}
}
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(u"qrc:/bbb/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
It seems your logging is somewhat truncated. Normally in this case (for me that is Qt5.11), that error is followed by the invalid property name 'text' that is visible in the designer, which is the real problem here.
You should keep in mind that signals and property are only visible/usable from the outside (so in your main.qml) if they are declared on the top most element in Button.qml. It seems you can simply remove the Item wrapping to make it work
Button.qml:
import QtQuick 2.0
Rectangle {
id: root
// export button properties
property alias text: label.text
signal clicked
width: 116; height: 26
color: "lightsteelblue"
border.color: "slategrey"
Text {
id: label
anchors.centerIn: parent
text: "Start"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.clicked()
}
}
}

Reusable confirmation prompt in QML

I need a confirmation or alert dialog when user presses a button. Based on if they choose 'yes' or 'no', different actions are triggered. The challenge is that I have two buttons which pops such a dialog and it's not quite straightforward how to do that in QML. Here is the code (my demo application):
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
function areYouSure()
{
prompt.visible = true
}
MainForm {
anchors.fill: parent
Button {
id: buttonA
anchors.left: parent.left
anchors.top: parent.top
text: "Button A"
onClicked: areYouSure() // based on yes or no, different actions but how to tell what was pressed?
}
Button {
id: buttonB
anchors.right: parent.right
anchors.top: parent.top
text: "Button B"
onClicked: areYouSure() // based on yes or no, different actions but how to tell what was pressed?
}
}
Prompt {
anchors.fill: parent
id: prompt
visible: false
onCancelled: {
console.log("Cancel was pressed")
// but how can I tell which button's cancel as pressed?
}
onAccepted: {
console.log("Accept was pressed")
// same for which button's Ok?
}
}
}
Prompt.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Rectangle
{
id: root
width: parent.width
property string message: "Are you Sure?"
signal cancelled;
signal accepted;
Text{
id: messagetxt
text:root.message
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: cancelButton
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Cancel"
}
color: "red"
MouseArea {
anchors.fill: parent
onClicked: {
root.visible = false
cancelled()
}
}
}
Rectangle {
id: okButton
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Ok"
}
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: {
root.visible = false
accepted()
}
}
}
}
In traditional programming, an individual dialog pops up which respond exactly to that question and than we respond to its cancelled() or accepted() signals. In QML we can't really do that, right? What is the best way to know which button was pressed? The irony is that even the right signals are emitted, we just can't seem to act on them.
Well, first and foremost you should really have a look at Dialogs module since it provides what would be a ready made solution for you, i.e. MessageDialog.
That said, you can achieve a customisation in different ways, including redefining the handlers or passing the ids. If the action to perform are simple (e.g. a function call) you can dynamically create even the dialog and bind the signals with the desired behaviour. Customisation can obviously go further, changing title and text.
Here is a simple example which follows the last approach and prints different texts depending on the pressed button. Once the dialog is set to not visible it is destroyed via the destroy function.
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0
ApplicationWindow {
id: win
title: qsTr("MultiDialog")
visible: true
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
onClicked: {
var d1 = compDialog.createObject(win)
// change "title" & "text"?
d1.accepted.connect(function(){
console.info("accepted: " + text)
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
})
d1.visible = true
}
}
Button {
text: "Button 2"
onClicked: {
var d2 = compDialog.createObject(win)
// change "title" & "text"?
d2.accepted.connect(function(){
console.info("accepted: " + text)
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
})
d2.visible = true
}
}
}
Component {
id: compDialog
MessageDialog {
title: "May I have your attention please"
text: "It's so cool that you are using Qt Quick."
onVisibleChanged: if(!visible) destroy(1)
standardButtons: StandardButton.Cancel | StandardButton.Ok
}
}
}
If you want to use Rectangle or are forced to use it, then you can still use this approach. Dynamic creation of objects is NOT related to the usage of MessageDialog and can be used (and should be used) to reduce the number of objects kept instanced throughout application lifetime. Have a look here for more details about that.
The following example uses the very same dialog component you defined (with some small modifications. As you can see the code is almost identical. I've just moved the destruction of the object at the end of the signal handlers. In this case I've also changed the value of the unique property defined in the component, i.e. message, to show you complete customization.
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
id: win
visible: true
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d1 = prompt.createObject(win)
d1.message = text + " - Are you Sure?"
d1.accepted.connect(function(){
console.info("accepted: " + text)
d1.destroy()
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
d1.destroy()
})
}
}
Button {
text: "Button 2"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d2 = prompt.createObject(win)
d2.message = text + " - Are you Sure?"
d2.accepted.connect(function(){
console.info("accepted: " + text)
d2.destroy()
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
d2.destroy()
})
}
}
}
Component {
id: prompt
Rectangle {
id: root
anchors.fill: parent
property string message: "Are you Sure?"
signal rejected()
signal accepted()
Text{
id: messagetxt
text:root.message
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
id: cancelButton
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Cancel"
}
color: "red"
MouseArea {
anchors.fill: parent
onClicked: rejected()
}
}
Rectangle {
id: okButton
anchors.bottom: parent.bottom
anchors.right: parent.right
width: 50
height: 40
Text {
anchors.centerIn: parent
text: "Ok"
}
color: "blue"
MouseArea {
anchors.fill: parent
onClicked: accepted()
}
}
}
}
}
If your component is not inlined as I did with Component but it's kept in another file you can use createComponent as depicted in the link provided above. The code of your main window would look like this:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
id: win
visible: true
property var prompt
RowLayout {
anchors.fill: parent
Button {
text: "Button 1"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d1 = prompt.createObject(win)
d1.message = text + " - Are you Sure?"
d1.accepted.connect(function(){
console.info("accepted: " + text)
d1.destroy()
})
d1.rejected.connect(function(){
console.info("rejected: " + text)
d1.destroy()
})
}
}
Button {
text: "Button 2"
Layout.alignment: Qt.AlignCenter
onClicked: {
var d2 = prompt.createObject(win)
d2.message = text + " - Are you Sure?"
d2.accepted.connect(function(){
console.info("accepted: " + text)
d2.destroy()
})
d2.rejected.connect(function(){
console.info("rejected: " + text)
d2.destroy()
})
}
}
}
Component.onCompleted: prompt = Qt.createComponent("Prompt.qml");
}
You should always check that component creation is correcly carried out (I didn't do it for the sake of brevity). That said, the code is identical to the previous one.
Last but not least, I've noticed an error in your code: signals must always be declared with parenthesis, even when no parameter is emitted. It should be signal accepted(), not signal accepted, same goes for the other signal and any other signal declaration.

QML TabView in ColumnLayout

I am trying to modify Gallery example. I want to add Button under TabView. So, I put TabView and Button into ColumnLayout, here is code:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Window 2.0
Window {
visible: true
title: "settings"
width: 600
height: 400
ColumnLayout{
anchors.fill: parent
TabView {
anchors.right: parent.right
anchors.left: parent.left
Tab {
title: "Controls"
Controls { }
}
Tab {
title: "Itemviews"
Controls { }
}
Tab {
title: "Styles"
Controls { }
}
Tab {
title: "Layouts"
Controls { }
}
}
RowLayout{
anchors.right: parent.right
anchors.left: parent.left
Button{
text: "ok"
}
}
}
}
However, when I resize window okButton stands under tab controls. How should I fix code?
When you have defined a Layout, each element added has access to specific properties related to the layout itself. These properties are useful to position the element inside the space covered from the layout. Confront what is described here.
Hence, you should modify the ColumnLayout like this:
ColumnLayout {
anchors.fill: parent
TabView {
id:frame
enabled: enabledCheck.checked
tabPosition: controlPage.item ? controlPage.item.tabPosition : Qt.TopEdge
Layout.fillHeight: true // fill the available space vertically
Layout.fillWidth: true // fill the available space horizontally
Layout.row: 0 // item in the first row of the column
anchors.margins: Qt.platform.os === "osx" ? 12 : 2
Tab {
id: controlPage
title: "Controls"
Controls { }
}
Tab {
title: "Itemviews"
ModelView { }
}
Tab {
title: "Styles"
Styles { anchors.fill: parent }
}
Tab {
title: "Layouts"
Layouts { anchors.fill:parent }
}
}
Button {
text: "ok"
Layout.row: 1 // item in the second row of the column
Layout.alignment: Qt.AlignCenter // simple center the button in its spatial slot
}
}
You don't need a RowLayout for the button. It should be placed in the second row of the ColumnLayout you have defined, since it is a simple component. A sub-layout could be useful in case of multiple elements on the same row, e.g. two or more buttons.
Note also that anchoring is just used for the ColumnLayout to "stretch" and fit the window. All the other operations are executed via the layout properties. For general rules take a look at this other article.

Prevent QML MouseArea from taking focus when pressed

In my application, I have a TextArea, and under it a toolbar with Button items. Whenever a Button gets pressed, the TextArea loses focus, and hides the virtual keyboard (which is right). But what if I want the TextArea to keep its focus, even if a Button has been pressed?
In SailfishOS, Button is just a MouseArea, not a QML Button. This means there is no property Button.activeFocusOnPress that I could set to false. Is there a way to replicate this behaviour for the MouseArea?
Here's some code:
TextArea {
id: editor
width: parent.width
height: 200
anchors.top: pageHeader.bottom
anchors.bottom: toolbar.top
}
ListModel {
id: textNavButtons
ListElement {buttonText: "left"}
ListElement {buttonText: "right"}
ListElement {buttonText: "tab"}
ListElement {buttonText: "home"}
ListElement {buttonText: "end"}
}
Row {
id: toolbar
anchors.bottom: parent.bottom
width: parent.width
height: 80
Repeater {
id: toolbarRepeater
model: textNavButtons
property int modelCount: model.count
delegate: Button {
text: buttonText
width: parent.width / toolbarRepeater.modelCount
onClicked: {
console.log("I was clicked: " + text);
}
}
}
}
EDIT: My goal is to use these buttons to insert tabs into the text, or to navigate with Home, End, Left, Right etc. I'm not sure if using these buttons will achieve the goal, but I had no other idea. I will have to simulate the keypress too.
Now you can use
delegate: Button {
text: buttonText
width: parent.width / toolbarRepeater.modelCount
focusPolicy: Qt.NoFocus
onClicked: {
console.log("I was clicked: " + text);
}
}

Customized radio button in qml

I want a window with 3 push button but this push buttons should work like radio button!
so this is my code:
Rectangle {
id: sideButton
color: sideButtonMouseArea.containsMouse ? '#DDDDDD' : '#F4F4F4'
property string text: 'Button'
MouseArea {
id: sideButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
parent.color = '#4872E8'
sideButtonLabel.color = '#E2EBFC'
}
}
Text {
id: sideButtonLabel
text: sideButton.text
font.pixelSize: 20
font.family: 'Tahoma'
anchors.centerIn: sideButton
color: '#787878'
}
}
I use this rectangle instead button but it has a proble when click on other button for 2end time
how could i fix it?
This code works for me:
MyRadioGroup.qml
import QtQuick 1.0
QtObject {
property Item selected : null
}
MyRadioButton.qml
import QtQuick 1.0
Rectangle {
id: sideButton
property string text: 'Button'
property MyRadioGroup radioGroup
color: radioGroup.selected === sideButton ? '#E2EBFC' :
(sideButtonMouseArea.containsMouse ? '#DDDDDD' : '#F4F4F4')
MouseArea {
id: sideButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: sideButton.radioGroup.selected = sideButton
}
Text {
id: sideButtonLabel
text: sideButton.text
font.pixelSize: 20
font.family: 'Tahoma'
anchors.centerIn: sideButton
color: radioGroup.selected === sideButton ? '#E2EBFC' : '#787878'
}
}
main.qml
import QtQuick 1.0
Rectangle {
height: 600
width: 600
MyRadioGroup {
id: radioGroup1
}
Column {
anchors.fill: parent
MyRadioButton {
anchors { left: parent.left; right: parent.right }
text: "Button 1"
radioGroup: radioGroup1
height: 100
}
MyRadioButton {
anchors { left: parent.left; right: parent.right }
text: "Button 2"
radioGroup: radioGroup1
height: 100
}
MyRadioButton {
anchors { left: parent.left; right: parent.right }
text: "Button 3"
radioGroup: radioGroup1
height: 100
}
MyRadioButton {
anchors { left: parent.left; right: parent.right }
text: "Button 4"
radioGroup: radioGroup1
height: 100
}
}
}
What it does: I've created container MyRadioGroup to hold currently selected item. Then, I declaratively bind its selected property with color property of my MyRadioButton-s, so it will update on every selected change.
Having that said, please check, that you component provider doesn't already contain some stuff like this --- maybe you are reinventing the wheel.