How to customize Popup closing behavior? - qt

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
}
}

Related

Can QML StackLayout detect drag from a component outside itself

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)

How to load and display QML file

I have two QML pages main.qml and Kos.qml,
what i want is when a button in main.qml clicked it load Kos.qml in the screen.
i did try using loader, but it is not working
import QtQuick 2.5
import QtQuick.Controls 2.5
ApplicationWindow {
id: applicationWindow
width: 640
height: 480
color: "#fc4343"
title: qsTr("Tabs")
visible: true
// HALAMAN UTAMA
Page {
anchors.centerIn: parent
anchors.fill: parent
id: page
enabled: true
Loader{
id: kos
active: true
anchors.fill: parent
}
Button {
id: button
x: 198
width: 87
height: 30
text: qsTr("Search")
font.bold: true
anchors.top: borderImage.bottom
anchors.topMargin: 198
anchors.right: toolSeparator.left
anchors.rightMargin: 28
MouseArea{
anchors.fill: parent
onClicked:{
kos.source = "Kos.qml";
}
}
background: Rectangle {
id: background
color: "#ef3644"
}
contentItem: Text {
id: textItem
font: control.font
opacity: enabled ? 1.0 : 0.3
color: "white"
text: "Search"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
}
}
Kos.qml i use PageBackground as a background
import QtQuick 2.4
PageBackground {
id: kos
width: 640
height: 480
Text {
id: element
x: 6
y: 20
width: 24
height: 32
color: "#ffffff"
text: qsTr("<")
font.strikeout: false
styleColor: "#ffffff"
font.underline: false
font.italic: false
font.bold: true
font.pixelSize: 25
MouseArea {
id: mouseArea
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.leftMargin: 0
anchors.topMargin: 0
anchors.fill: parent
}
}
}
did i messed up somewhere?
I tried to run your code. Since I am not aware of what your PageBackground is, I changed that to Rectangle. That works for me. Try to start from the minimal code then add your styles and functions on top of it. Try with below minimal code. Keep both main.qml & Kos.qml in the same directory and ensure both files added to qml resources.
main.qml
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
id: applicationWindow
width: 640
height: 480
visible: true
Text {
anchors.centerIn: parent
text: "App window"
}
Loader {
id: loaderId
anchors.fill: parent
source: ""
}
Button {
text: "click me!!"
width: parent.width
anchors.bottom: parent.bottom
onClicked: {
if(loaderId.source == "")
loaderId.source = "Kos.qml"
else
loaderId.source = ""
}
}
}
Kos.qml
import QtQuick 2.9
Rectangle {
id: kos
width: 640
height: 480
color: "grey"
Text {
anchors.centerIn: parent
text: "<b>Loaded Item</b>"
color: "white"
}
}

How to add element directly to the child of custom module in qml?

How to add element directly to the child of custom module in qml?
There are three Rectangle(rect1/rect2/rect3) below as the content of ScrollView
import QtQuick 2.12
import QtQuick.Controls 2.12
ScrollView {
property var content
clip: true
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
Rectangle {
width: parent.width
height: c.height
implicitHeight: c.height
Column {
id: c
spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
// Contents
Rectangle{
id: rect1
width: 100
height: 200
color: "#ffff00"
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle{
id: rect2
width: 100
height: 200
color: "#000000"
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle{
id: rect3
width: 100
height: 200
color: "#00ffff"
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
}
But each time writing to the above is more complicated
I want to encapsulate the above code into MyScrollView.qml module
I want to use it like this
MyScrollView {
Rectangle {
id: rect1
width: 100
height: 200
color: "#ffff00"
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle {
id: rect2
width: 100
height: 200
color: "#000000"
anchors.horizontalCenter: parent.horizontalCenter
}
Rectangle {
id: rect3
width: 100
height: 200
color: "#00ffff"
anchors.horizontalCenter: parent.horizontalCenter
}
}
Is it possible for qml to do this? If not, how to write the most elegant?
You could achive this using different approaches, for example there is Qt.createComponent for dynamic object creations on the fly
or you can assign alias property to reference some internal central object to assign Items
Or you can use Loader to load components.
I'll show example based on your wishes in topic :)
create MyScrollView.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
ScrollView {
property list<Item> content_list
clip: true
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
Component.onCompleted:
{
for(var i = 0; i < content_list.length; i++)
{
content_list[i].parent = c;
}
}
Rectangle
{
width: parent.width
height: c.height
implicitHeight: c.height
Column
{
id: c
spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
And somewhere use it like so:
MyScrollView{content_list: [
Rectangle {
id: rect1
width: 100
height: 200
color: "#ffff00"
anchors.horizontalCenter: parent.horizontalCenter
},
Rectangle {
id: rect2
width: 100
height: 200
color: "#000000"
anchors.horizontalCenter: parent.horizontalCenter
},
Rectangle {
id: rect3
width: 100
height: 200
color: "#00ffff"
anchors.horizontalCenter: parent.horizontalCenter
}
]}

How can I call a custom signal from a QML Component?

Is there a way to call a signal from a mouseArea included in a component which is loaded somewhere else?
onClicked in the example below is not entered when i click on the rectangle.
The structure needs to remain as defined. To be able to define a qml component that applies a shadow to any source
Here is the code:
Window{
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item
{
id: mainRectangle
anchors.centerIn: parent
width: loaderId.width + 60
height: loaderId.height + 60
Rectangle {
id: rect2
anchors.right: mainRectangle.right
anchors.top: mainRectangle.top
anchors.rightMargin: -30
anchors.topMargin: -30
width: 100
height: 100
color: "red"
opacity: 0.5
}
Loader {
id: loaderId
anchors.centerIn: parent
sourceComponent: component
active:true
}
visible: false
}
ShaderEffectSource {
id: shader
anchors.fill: mainRectangle
anchors.margins: -30
sourceItem: mainRectangle
opacity: 0.5
visible: true
}
Component {
id: component
Rectangle {
id: rect
width: 100
height: 100
color: "black"
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Clicked!")
// call a signal from here
}
}
}
}
}
In the end the should show what it does now and the mouseArea should work.
onClicked in the example below is not entered when i click on the rectangle.
mainRectangle is not visible, and items that aren't visible don't get input events. Since the MouseArea is a child of mainRectangle, it won't get events either.
In the end the should show what it does now and the mouseArea should work.
Instead of hiding the source item and using ShaderEffectSource, you can set the opacity directly on mainRectangle and use item layers (the link has a similar example) to ensure that there is no overlap due to transparency:
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Item {
id: mainRectangle
anchors.centerIn: parent
width: loaderId.width + 60
height: loaderId.height + 60
opacity: 0.5
layer.enabled: true
Rectangle {
id: rect2
anchors.right: mainRectangle.right
anchors.top: mainRectangle.top
anchors.rightMargin: -30
anchors.topMargin: -30
width: 100
height: 100
color: "red"
}
Loader {
id: loaderId
anchors.centerIn: parent
sourceComponent: component
active: true
}
}
Component {
id: component
Rectangle {
id: rect
width: 100
height: 100
color: "black"
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Clicked!")
// call a signal from here
}
}
}
}
}

QML pieMenu on draggable object

I've got a draggable object that is created by a Javascript, which is working fine. But when I create a PieMenu inside it, the object isn't created/visible in the Javascript context:
import QtQuick 2.8
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4
import QtQml.Models 2.2
Rectangle {
id: rev
width: 100
height: 80
color: "transparent"
antialiasing: false
Drag.active: dragArea.drag.active
MouseArea {
id: dragArea
width: parent.width
height: parent.height + 10 // easier to get
anchors.centerIn: parent
drag.target: parent
drag.axis: Drag.XAndYAxis
onClicked: pieMenu.popup(mouseX, mouseY), console.log("clicked")
}
PieMenu {
id: pieMenu
MenuItem {
text: "Add vertical bar"
onTriggered: print("Action 2")
}
}
Gauge {
id: revgauge
anchors.fill: parent
anchors.margins: 10
orientation : Qt.Horizontal
minorTickmarkCount: 4
tickmarkStepSize : 5000
minimumValue: 0
maximumValue: 10000
Behavior on value {
NumberAnimation {
duration: 5
}
}
Text {
font.pixelSize: (parent.height / 3)
anchors.top : parent.top
font.bold: true
font.family: "Eurostile"
color: "white"
anchors.horizontalCenter: parent.horizontalCenter
}
style: GaugeStyle {
valueBar: Rectangle {
implicitWidth: rev.height /3
color: Qt.rgba(revgauge.value / revgauge.maximumValue, 0, 1 - revgauge.value / revgauge.maximumValue, 1)
}
}
}
}
Can Mousearea handle dragging and a PieMenu at once? If not how can it be solved?
Consider QML PieMenu boundingItem. It addresses an exact issue with MouseArea you presented.

Resources