I have a StackLayout with 3 stack items (2 static and one dynamically generated) which switches on button click. I want to make the second and third stack items a Droparea (third one is dynamically created) where I want to drag items from a Listview which is outside the StackLayout. Is it possible or I am doing something wrong?
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page{
id: pageid
width: parent.width
height: parent.height
Row{
id: row1
Button{
text: "0"
onClicked: layout.currentIndex = 0
}
Button{
text: "1"
onClicked: layout.currentIndex = 1
}
Button{
text: "2"
onClicked:{
var str = 'import QtQuick 2.15; Rectangle {id: rect2; color: "red"; DropArea{anchors.fill: parent; onEntered: {rect2.color = "silver"}}}'
var comp = Qt.createQmlObject(str,layout,"dynamicSnippet1")
onClicked: layout.currentIndex = 2
}
}
}
// Stacklayout block
StackLayout {
id: layout
anchors.top: row1.bottom
height: parent.height - row1.height - dragger.height
width: parent.width
currentIndex: 0
// Component 0
Rectangle {
id: rect0
color: 'teal'
}
// Component 1
Rectangle {
id:rect1
color: 'plum'
DropArea{
anchors.fill: parent
onEntered: {rect1.color = "gold"}
}
}
}
// Drag rectangles
ListView{
id: dragger
anchors.top: layout.bottom
height: 30
width: parent.width
orientation: Qt.Horizontal
model: 3
delegate: Rectangle{
id: xrect
height: 30
width: 60
color:"grey"
border.width: 1
border.color: "orange"
MouseArea{
id: ma
anchors.fill: parent
onReleased: parent.Drag.drop()
drag.target: parent
}
}
}
}
You forgot to set property Drag.active for your draggable target, e.g. put statement
Drag.active: ma.drag.active
into your xrect to make it work.
In addition you could check more dragging signals in your DropArea:
onDropped: console.error("# dropped")
onContainsDragChanged: console.error("# containsDrag", containsDrag)
Related
I have some simulated buttons in on rectangle. These buttons I need at different places in the app. Is it possible to make a kind of component out of it?
This is how it is currently
RowLayout {
anchors.fill: parent
Rectangle {
id: button1
height: _buttonsHeight * 0.6
width: height
radius: height / 2
border.width: 1
border.color: "black"
Image {
anchors.centerIn: parent
source: "image://iconProvider/icons/128/button1.png"
sourceSize.height: parent.height * 0.8
}
MouseArea {
anchors.fill: parent
onPressed: btnHome.border.width = 2
onReleased: btnHome.border.width = 0
onClicked: userInputDevice.buttonClicked("button1")
}
}
Rectangle {
id: button2
height: _buttonsHeight * 0.6
width: height
radius: height / 2
border.width: 1
border.color: "black"
Image {
anchors.centerIn: parent
source: "image://iconProvider/icons/128/button2.png"
sourceSize.height: parent.height * 0.8
}
MouseArea {
anchors.fill: parent
onPressed: btnHome.border.width = 2
onReleased: btnHome.border.width = 0
onClicked: userInputDevice.buttonClicked("button2")
}
}
}
Something like this would be the goal
RowLayout {
anchors.fill: parent
Button {id = "button1", height = _buttonsHeight * 0.6, icon = "button1.png", command = "button1", parent = this}
Button {id = "button2", height = _buttonsHeight * 0.6, icon = "button2.png", command = "button2", parent = this}
}
Is something like this feasible ?
Thanks and best regards
Arne
You should read the documentation about QML defining types.
Don't use the assignment operator, but the colon to create bindings. No need to set any parent.
For the nested Image.source property you should create an alias property in the root of your component like so property alias imageSource: <imageID>.source to be able to set it from the outside.
import QtQuick
import QtQuick.Layouts
Window {
id: root
width: 320
height: 240
visible: true
property int btnHeight: 80
component CustomButton : Rectangle {
property alias icon: image.source
signal pressed
signal released
signal clicked
id: buttonRoot
height: 20
width: height
radius: height / 2
border.width: 1
border.color: "black"
Image {
id: image
anchors.centerIn: parent
source: "https://upload.wikimedia.org/wikipedia/commons/7/72/Variable_Resistor.svg"
fillMode: Image.PreserveAspectFit
width: buttonRoot.height / Math.sqrt(2)
height: image.width
}
MouseArea {
anchors.fill: parent
onPressed: buttonRoot.pressed()
onReleased: buttonRoot.released()
onClicked: buttonRoot.clicked()
}
}
RowLayout {
anchors.centerIn: parent
spacing: 20
CustomButton {
id: button1
height: root.btnHeight
onClicked: console.log("Button 1 clicked")
}
CustomButton {
id: button2
height: root.btnHeight
icon: "https://upload.wikimedia.org/wikipedia/commons/f/fd/Crystal_Clear_app_download_manager.svg"
onClicked: console.log("Button 2 clicked")
}
}
}
You can create a new qml file let's name it MyButton.qml
MyButton is a custom button with icon and text you can change it to fit your needs.
MyButton.qml:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import Qt.labs.platform 1.0
import QtLocation 5.12
import QtQuick.Controls.Material 2.15
MouseArea {
id: control
width: control.w
height: control.h
property string icon_btn
property bool icon_visible: true
property string text
property int border: 3
property string borderColor: "white"
property string colorr: "#222222"
property int w: 50
property int h: 50
property bool text_visible: true
property bool clicked: false
property int radius: 12
property int contentLeftMargin: 0
property string buttonColor: enabled ? control.colorr : "grey"
cursorShape: Qt.PointingHandCursor
Rectangle {
border.color: control.borderColor
border.width: control.border
radius: control.radius
anchors.fill: parent
color: control.buttonColor
RowLayout{
anchors.fill: parent
Item { Layout.fillWidth: true }
Image{
id: img
visible: control.icon_visible
source: control.icon_btn
Layout.preferredWidth: 35
Layout.preferredHeight: 35
//Layout.leftMargin: control.contentLeftMargin
}
Text{
id: txt
text: control.text
font.pointSize: 17
font.bold: true
color: "white"
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
visible: control.text_visible ? x + width + 15 < control.width : 0
//Layout.leftMargin: control.contentLeftMargin
}
Item { Layout.fillWidth: true }
}
}
Layout.bottomMargin: 10
}
Then use it in your main qml file.
For example:
Window {
MyButton{
id: btn_refresh
icon_btn: "qrc:/Icons/outline_refresh_white_48pt_3x.png"
onClicked: {
//do something on click
}
}
}
I created a control, and when I click it, the popup will be displayed on the left and right sides. Like:
There may be many other buttons on the main interface. I hope that when I click the button, the popup will not close, but when I click other external areas, the popup will close.
I thought of using closePolicy, but when I set Popup.NoAutoClose, no matter I click the outer area or the button control, the popup will not be closed. When I set Popup.CloseOnPressOutside, the popup will be closed.
So how to customize the closing behavior of the popup? Or is there any other custom control way to achieve such a requirement(may not be popup)?
Edit
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
MenuSpinner{
id: menuId
x: 100
y: 50
}
Column{
x: 500
spacing: 10
Repeater{
model: 3
Button{
width: 100
height: 50
text: index
onPressed: {
console.log("pressed" + index)
}
}
}
}
}
MenuSpinner.qml
import QtQuick 2.0
import QtQuick.Controls 2.5
Rectangle{
width: 300
height: 50
property bool bTextClicked: false
onBTextClickedChanged: {
if(bTextClicked) popup.open()
else popup.close()
}
Rectangle{
width: 100
height: parent.height
x: rect1.width
border.color: "blue"
Text {
id: text
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: qsTr("value")
font.pixelSize: 16
}
MouseArea{
anchors.fill: parent
onClicked: {
bTextClicked = !bTextClicked
}
}
}
Popup {
id: popup
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
width: parent.width
height: parent.height
background: Rectangle {
anchors.fill: parent
color: "transparent"
//border.color: "black"
}
Rectangle{
id: rect1
width: 100
height: 50
Text {
text: qsTr("pop1")
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 16
}
color: "transparent"
border.color: "blue"
}
Rectangle{
id: rect2
x: parent.width - rect1.width
width: 100
height: 50
Text {
text: qsTr("pop2")
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 16
}
color: "transparent"
border.color: "blue"
}
onClosed: {
bTextClicked = false
console.log("close")
}
}
}
One way to do it is to catch mouse clicks on the window itself. Add a function or signal to MenuSpinner that can be called to close the popup. Any clicks to the other buttons should still work.
main.qml
Window {
MouseArea {
anchors.fill: parent
onClicked: {
menuId.closePopup();
}
}
MenuSpinner{
id: menuId
}
}
MenuSpinner.qml
Rectangle{
function closePopup() {
popup.close();
}
Popup {
id: popup
closePolicy: Popup.NoAutoClose
}
}
My program consisted of a tabbar and stackLayout. I face a layout problem that the tab button is too close to the head of the listview as shown below. They are horizontally aligned together.
But I want the listview to be under the tab button. I tried adding the topMargin in the listview, but it doesn't have any effect at all. Please help.
The code:
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtMultimedia 5.8
import QtQuick.Layouts 1.3
import com.contentplayermod.filemodel 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Tabs")
property int idx: 0
property bool isActive: true
TabBar {
id: bar
width: parent.width
TabButton {
text: qsTr("Main")
}
TabButton {
text: qsTr("View")
}
}
StackLayout {
id: stackLayout
height:parent.height
width: parent.width
currentIndex: bar.currentIndex
Item {
id: mainTab
anchors {
topMargin:60
}
width: 500
height:800
ListView {
id: lv
anchors.margins: 50
width: 200; height: 400
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
currentIndex: 0
Component {
id: fileDelegate
Text {
text: fileName
font.pointSize: 20
anchors {
topMargin:60
}
MouseArea{
anchors.fill: parent
}
}
}
model: FileModel{
id: myModel
folder: "c:\\folder"
nameFilters: ["*.mp4","*.jpg"]
}
delegate: fileDelegate
highlightFollowsCurrentItem: true
}
}
Item {
id: viewTab
width: 500
height:800
}
}
}
You can either anchors your stack-top to the bottom of the tab bar like this :
...
StackLayout {
id: stackLayout
height:parent.height - bar.height
anchors.top: bar.bottom
width: parent.width
...
Or much simpler, put everything in a ColumnLayout :
ColumnLayout {
anchors.fill: parent
TabBar {
id: bar
Layout.fillWidth: true
...
}
StackLayout {
id: stackLayout
Layout.fillHeight: true
Layout.fillWidth: true
...
}
}
So you don't have to deal with width and height, and it's more easy to insert new widgets in your window.
You can add spacing to the ColumnLayout to put some space between the TabBar and the content. Or manage this inside the Items displayed by the StackLayout for more flexibility.
I have Rectangle filled with MouseArea which on onPressAndHold() handler reveals second Rectangle and transfers drag action to that Rectangle. The problem is that when I move that second Rectangle over DropArea it doesn't notify about any actions (onEntered, onExited, onDropped). I tried to do this in many combinations but it has never worked. Here is an example, am I missing something?
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
id: appDrawerRoot
visible: true
width: 360; height: 360
property bool isRectVisible: false
Rectangle{
id:rect
color: "blue"
x:50; y:50
width: 50; height: 50
MouseArea{
anchors.fill: parent
onPressed: {
cloneRect.x = rect.x
cloneRect.y = rect.y
}
onPressAndHold: {
isRectVisible = true
drag.target = cloneRect
}
onReleased: {
drag.target = undefined
isRectVisible = false
cloneRect.x = rect.x
cloneRect.y = rect.y +100
}
}
}
Item{
id: cloneRect
width: 50; height:50
visible: isRectVisible
MouseArea{
id: mouseArea
width:50; height:50
anchors.centerIn: parent
Rectangle{
id:tile
width: 50; height:50
color:"black"
opacity: 0.5
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Drag.hotSpot.x: 25
Drag.hotSpot.y: 25
}
}
}
DropArea {
id:dropArea
x:153
y:158
z:-1
width:100; height: 100
Rectangle{
anchors.fill: parent
color: "Green"
}
onEntered: {
drag.source.opacity = 1
console.log("ENTERED")
}
onExited: {
drag.source.opacity = 0.5
console.log("EXITED")
}
onDropped:
{
console.log("DROPPED")
}
}
}
The main problem with your code is that you don't set the active property of the drag. Modify you code like this:
//..........................
Item{
id: cloneRect
width: 50; height:50
visible: isRectVisible
Drag.active: visible // Add this line of code
//.....................
For more information please refer to Qt examples. At Qt Creator's "Welcome" screen hit "Examples" button and search for "drag and drop qml".
I'm working on a QML StackView that starts with a list of items to select from. Once selected I want to transition _.push(...) to a input form which has larger dimensions than the initialItem.
The only way I have trial-and-errored my way into a situation that works is by making the form Item a nested borderless window.
Q1. A nested window can't be the right type of concept to use for this... right ? there must be another way to do it. What is the right way ?
Q2. My goal after this is to have a transition animation that grows or shrinks between stacks of different sizes. Advice that doesn't preclude that would be best.
code
Main.qml :
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
ApplicationWindow {
property int itemHeight: 30
property int cornerRadius : 5
visible: true
color: "transparent"
flags: Qt.FramelessWindowHint
ListModel {
id: searchFacets
ListElement {
title: "Topics"
page: "content/TopicSearch.qml"
}
// ListElement {
// title: "Domains"
// }
}
StackView {
id: stackView
focus: true
initialItem: SearchFacets {
id: facets
}
delegate: StackViewDelegate {
pushTransition: StackViewTransition {
PropertyAnimation {
target: enterItem
property: "opacity"
from: 0
to: 1
}
}
}
}
}
Initial Item:
import QtQuick 2.3
Item {
height : listView.count * itemHeight
ListView {
id: listView
model: searchFacets
anchors.fill: parent
focus: true
highlightFollowsCurrentItem: false
highlight: Rectangle {
width: parent.width
height: itemHeight
radius : cornerRadius
color: "green"
opacity: 0.5
z:2
x: listView.currentItem.x;
y: listView.currentItem.y
Behavior on y {
SpringAnimation {
spring: 60
damping: 1.0
}
}
}
delegate: Component {
Item {
width: parent.width
height : itemHeight
Rectangle {
anchors.fill: parent
color: "#212126"
radius: cornerRadius
z:0
border.width: 2
border.color : "white"
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
console.log("clicked index: " + index)
listView.currentIndex = index
// listView.forceActiveFocus()
stackView.push(Qt.resolvedUrl(page))
}
}
Text {
text: title
font.pixelSize: 24
font.bold: true
z:1
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: "white"
antialiasing: true
}
}
}
}
}
Input Form:
import QtQuick 2.3
import QtQuick.Window 2.0
Item {
Window {
width: 400
height: 400
visible: true
flags: Qt.FramelessWindowHint
Rectangle {
anchors.fill: parent
visible: true
color: "red"
}
}
}
One possible solution is to update the size of the dimensions of the StackView in the click handler that causes the transition. I do not know if that causes any problems with animating the transition.
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
console.log("clicked index: " + index)
listView.currentIndex = index
var component = Qt.createComponent(page)
var res = component.createObject(stackView)
stackView.height = res.height
stackView.width = res.width
stackView.push(res)
}
}