QML , How to Access Element from Another qml - qt

I want to ask simple question for quick solution. I have ListView and Button in main.qml and Component in closingtaskdelage.qml. Here is file main.qml:
ListView
{
id: grid
delegate:mydelegate
model: mymodel
spacing: 5
orientation:ListView.Vertical
Layout.preferredWidth: width_commmon
Layout.preferredHeight: height_body
Layout.maximumHeight: 800
Layout.alignment: Qt.AlignHCenter
// highlightFollowsCurrentItem: false
focus: true
ClosingTaskModel
{
id:mymodel
}
ClosingTaskDelegate
{
id:mydelegate
}
}
Button
{
id:finishbutton
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: width_commmon
Layout.preferredHeight:height_endbutton
text: "İş Emrini Tamamla"
onClicked:
{
// console.log((grid.children["border1"]).id);
}
}
and file ClosingTaskDelegate.qml:
Component
{
id:component1
Rectangle
{
signal sendMenuValuestoJS
height: 200
width: 200
Text
{
id:text1;
text:header;
height:parent.height/2
// width: parent.width
anchors.horizontalCenter:parent.horizontalCenter;
font.pointSize:20;
color:"red";
// height:parent.height/2
// width: parent.width
}
}
}
Don't care about details. My main problem is: When onClickButton() in main.qml occurs, signal sendMenuValuestoJS() must be triggered. This signal must send string value as parameter (i.e. send Text).
I can't access signal from main.qml. I have defined signal in the Component, but I get following runtime QML error:
Component objects cannot declare new signals.
How do I connect signal to some function?

What about to to use Connections?
Here is the idea,
/* main.qml */
Rectangle {
width: 200
height: 200
MouseArea {
id: mouse
anchors.fill: parent
}
Click {
id: click
targetto: mouse
}
}
/* Click.qml */
Item {
property variant targetto
Connections {
target: targetto
onClicked: console.log("CLICKED!");
}
}

Here is example from official Qt webiste in Signal Handler Attributes chapter.

Related

Send a signal between two object instances in different QML files

I'm trying to send a signal from an object in one QML file to another object in a different QML file, but can't seem to find any good resources to use as a guide. Most of the examples I have come across show signals and slots being used to communicate between either two objects implemented in the same QML file (i.e. inside the same component), or in two different component files that come together inside a third QML file, which differs from my use case.
I need to send a string value from an object in a QML file (which represents a screen) to another object in a different QML file (representing yet another screen). The way the screens are linked currently is via StackView QML type in the main.qml file.
The closest I have seen the same problem described is here. The problem with the accepted answer in my case is the fact that the objects Rect1 and Rect2 are later defined in the same file. This means that they can be given an id and the signal and slot can be connected together, something I'm unable to do on my side.
Here's some code to demonstrate the problem.
main.qml:
ApplicationWindow {
id: app_container
width: 480
height: 600
visible: true
StackView {
id: screen_stack
anchors.fill: parent
initialItem: Screen1 {
}
}
}
Screen1:
Item {
id: screen_1
width: 480
height: 600
property var input
TextField {
id: user_input
width: parent.width
height: parent.height - 100
anchors.horizontalCenter: parent.horizontalCenter
placeholderText: qsTr("Enter your name")
onEditingFinsihed: {
input = user_input.text
}
}
Button {
width: parent.width
height: 100
anchors.top: user_input.bottom
anchors.horizontalCenter: parent.horizontalCenter
onClicked: {
console.log("Moving to Screen2")
screen_stack.push("qrc:/Screen2.qml")
}
}
}
Screen2:
Item {
id: screen_2
width: 480
height: 600
Rectangle {
anchors.fill: parent
color: "yellow"
Text {
id: txt_rect
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: qsTr("")
}
}
}
What I would like to be able to do is send the user input from TextField user_input in Screen1 to Text txt_rect in Screen2. How can I achieve this?
You can push properties:
screen_stack.push("qrc:/Screen2.qml", {"inputText": user_input.text})
Screen2:
Item {
id: screen_2
width: 480
height: 600
property var inputText
Rectangle {
anchors.fill: parent
color: "yellow"
Text {
id: txt_rect
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
text: screen_2.inputText
}
}
}

QML SplitView auto collapse on handlebar mouse release

I have a QML Controls 2 SplitView and a redefined handle, which works well, but I want detect mouse release event on the handler, so I could collapse the SplitView under a certain threshold of width. Adding a MouseArea on top of the existing handle will absorb drag events, so I'm unable to move the handlebar. Any idea how could I gather the mouse release event, or any other solution which solves this problem?
Alright, I have created an example application. As you can see in this example, my MouseArea is marked with yellow and collapses the right view programmatically when double clicked, which is nice, but I also want to drag the handlebar and upon mouse release under a certain width threshold I want to collapse the view as well. The black part of the handlebar where my MouseArea is not covering the handlebar, responds to drag, but since there is no signal I can gather from it, the width threshold already set shouldCollapse boolean property, so the view won't update. Probably I could solve this issue with a timer, but I need a more sophisticated solution.
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 800
height: 400
visible: true
SplitView {
id: splitView
anchors.fill: parent
orientation: Qt.Horizontal
function toggleCollapse() { collapsibleRect.shouldCollapse = !collapsibleRect.shouldCollapse }
handle: Rectangle {
implicitWidth: 20
implicitHeight: 20
color: "black"
MouseArea {
anchors.centerIn: parent
width: parent.width
height: parent.height / 2
onDoubleClicked: splitView.toggleCollapse()
Rectangle {
anchors.fill: parent
color: "yellow"
Text {
anchors.centerIn: parent
text: "Double click to collapse"
rotation: 90
}
}
}
}
Rectangle {
id: mainRect
color: "green"
SplitView.fillWidth: true
Text {
anchors.centerIn: parent
font.pixelSize: 24
text: "Main scene"
}
}
Rectangle {
id: collapsibleRect
property bool shouldCollapse: false
SplitView.preferredWidth: shouldCollapse ? 0 : 300
color: "purple"
clip: true
onWidthChanged: {
if(width < 200) shouldCollapse = true
else shouldCollapse = false
}
Text {
anchors.centerIn: parent
rotation: parent.shouldCollapse ? 90 : 0
font.pixelSize: 24
text: parent.shouldCollapse ? "SHOULD BE COLLAPSED" : "NOT COLLAPSED"
Behavior on rotation { NumberAnimation { duration: 100 } }
}
}
}
}
I had a similar problem and was able to solve it thanks to the hint of #Ponzifex that the SplitView's resizing property will be set to true as soon as the handle is clicked. Using a Timer I managed to detect whether the handle was quickly pressed twice in a row.
SplitView {
id: view
...
handle: Rectangle {
...
}
//============================================================
// double click behavior
Timer {
id: doubleClickTimer
interval: 300 // number of ms between clicks that should be considered a double click
}
property bool doubleClicked: false
// `resizing` will be set to true even if the handle is just pressed
onResizingChanged: {
if (view.resizing) {
if (!doubleClickTimer.running) {
doubleClickTimer.start();
return;
}
view.doubleClicked = true;
} else {
if (view.doubleClicked) {
// do any manual resizing in here
view.doubleClicked = false;
}
}
}
}
It is important to note, however, that it is only possible to resize the contents of a SplitView when resizing is false. That's why I need to have the doubleClicked helper property.
Add this to MouseArea:
onPressed: {
mouse.accepted = (mouse.flags & Qt.MouseEventCreatedDoubleClick);
}
propagateComposedEvents: true
cursorShape: Qt.SplitHCursor

QML StackView, how to navigate within the pushed item?

My app has a stackview that has two QML files.
And I need to navigate from one QML file to another from inside that QML file itself where I won't have access to stackview to push or pop.
How should I design this?
Main.qml
Rectangle
{
id: mainBkg
color: "white"
width: Screen.width
height: Screen.height
//Tickes every globalTimer.interval
property int globalTick: 0
Statusbar
{
width: Screen.width
height: Screen.height*0.2
id: statusBar
Rectangle
{
width: parent.width
height: parent.height*0.2
anchors.fill: parent
color: "green"
Text {
id: t
text: qsTr("QMLfile1")
}
}
}//end of statusbar
StackView {
id: stackView
anchors.top: statusBar.bottom
anchors.centerIn: parent
//What should be here? So that stackView
//will be available inside the loaded items.
initialItem:
}
}
Following are the two QML files:
QMLfile1.qml
Rectangle
{
width: parent.width
height: parent.height*0.2
anchors.fill: parent
color: "green"
Text {
id: t
text: qsTr("QMLfile1")
}
MouseArea:{
onClicked: //move to other QML file in stackview
}
}
I have another QML file like the above one.
You have tons of options.
One would be, to add a signal to the root-element of the QMLfile1.qml, and connect to it in the main.qml. The change will be performed there.
You can also add a property var callback to the root-element of the QMLfile1.qml where you inject the push-method of the StackView when instantiating it.
Finally you can just not shadow the id of the StackView and access it across file boundaries. I generally don't like that.

Make BusyIndicator run when click on button (signal to C++)

I created an interface has a ListView and two Buttons. When click on Scan button it will call to C++ and make change to the model of ListView. After that C++ will emit signal to inform model is changed therefore ListView in QML will update with new model. I want to make BusyIndicator running during that process. How can i do that ?.
I saw a few solutions on stackoverflow like this one: BusyIndicator does not show up but none of them worked for my case.
Can anyone help me ? Thanks.
Here is my qml code:
import QtQuick 2.5
import QtQuick.Layouts 1.3
import Qt.labs.controls 1.0
Rectangle
{
objectName: "bluetoothPage"
anchors.fill: parent
property var bluetoothDataModel: messageFromApp.bluetoothData
onBluetoothDataModelChanged: listView.update()
signal qmlScanButtonSignal()
signal qmlDisconnectButtonSignal()
ColumnLayout
{
anchors.fill: parent
spacing: 6
RowLayout
{
Layout.fillWidth: true
Text
{
Layout.fillWidth: true
text: "Connect with ECU"
font.bold: true
font.pixelSize: 20
}
BusyIndicator
{
id: busyIndicator
Layout.preferredWidth: 30
Layout.preferredHeight: 30
running: false
visible: false
}
}
GroupBox
{
Layout.fillHeight: true
Layout.fillWidth: true
title: qsTr("Available device:")
ListView
{
id: listView
anchors.fill: parent
model: bluetoothDataModel
delegate: Component
{
Item
{
width: parent.width
height: 40
Column
{
Text { text: "Name:" + model.modelData.name }
Text { text: "Number:" + model.modelData.macAddress }
}
MouseArea
{
anchors.fill: parent
onClicked: listView.currentIndex = index
}
}
}
highlight: Rectangle
{
color: "blue"
}
}
}
RowLayout
{
Layout.fillWidth: true
Layout.preferredHeight: 10
Button
{
Layout.fillHeight: true
Layout.fillWidth: true
text: "Scan"
onClicked: qmlScanButtonSignal()
}
Button
{
Layout.fillHeight: true
Layout.fillWidth: true
text: "Disconnect"
onClicked: qmlDisconnectButtonSignal()
}
}
}
}
Only this solution worked for me in my case. However, like everybody said using QCoreApplication::processEvents()
is really bad practice. I also try to using QThread but it got crash when emitted signal inside thread. If you guy have any futher solutions, please let me now. I'm really appreciate. Thanks.
QML
BusyIndicator {
running: CPPModule.busy
}
CPP
void CPPModule::setBusy(const bool &busy)
{
m_busy = busy;
emit busyChanged();
}
void CPPModule::InsertIntoDB()
{
setBusy(true);
QThread::msleep(50);
QCoreApplication::processEvents();
/*
very Long Operation
*/
setBusy(false);
}
Another solution is this:
Timer {
id: myTimer
interval: 1
onTriggered: {
app.someLongRunningFunction();
myActivityIndicator.visible = false;
}
}
Butoon{
....
onClicked: {
myActivityIndicator.visible=true;
myTimer.start();
}
}

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

Resources