QML How to open new page onClick with a Loader - qt

I have an app that consists of multiple plages. And user will be able to switch between these pages by button clicks. When I put a Window {} in Kontrolpage.qml, it gives me EGLFS: OpenGL windows cannot be mixed with others error. So I put an Item in Kontrolpage.qml. In that way when I press the button, item gets opened. However, it looks small. Eventhough I set the size constraints in Kontrolpage.qml to 640-480 which is same as the size of the main.qml. So main qml still visible in the background and on top of it newly opened qml is visible but it's not fullscreen. How can I fix that thing and what I am doing wrong?
Window {
id:main
width:640
height:480
Image
{
objectName: "background"
width: parent.width
height: parent.height
source:"Imgs/Images/bckgnd.png"
LeftButtons
{
id:buttonKontrol
x: -20
y:110
buttonName: "kontrol"
Loader { id: kontrolPageLoader}
MultiPointTouchArea
{
id:touchArea_kontrol
anchors.fill:parent
onPressed:
{
kontrolPageLoader.source ="KontrolPage.qml"
}
}
}
}
And here is the Kontrolpage.qml:
Item{
visible:true
width:640
height:480
Image {
objectName:"background"
width:parent.width
height:parent.height
source:"Imgs/Images/bckgnd"
}
}
Edit: When I put Loader outside of the LeftButtons and into window {} as :
Window {
id:main
width:640
height:480
Loader { id: kontrolPageLoader}
Image
{
objectName: "background"
width: parent.width
height: parent.height
source:"Imgs/Images/bckgnd.png"
LeftButtons
{
id:buttonKontrol
x: -20
y:110
buttonName: "kontrol"
MultiPointTouchArea
{
id:touchArea_kontrol
anchors.fill:parent
onPressed:
{
kontrolPageLoader.source ="KontrolPage.qml"
}
}
}
}
It does not open the new page. And keeping the loader inside the LeftButtons, when I use anchors.fill:parent, it resize it according to parent LeftButtons. However, I want to have the size of my Window in the new Page. The main problem in here looks like, why I cannot put Loader out of Leftbuttons and in Window?
Complete code for main.qml:
import QtQuick 2.11
import QtQuick.Window 2.11
Window {
id:main
visible: true
width: 640
height: 480
//Constant Definitions
readonly property string textColorBlue: "#8ccae5"
readonly property string textColorRed: "#dc0000"
Item {
id: backgroundItem
width:main.width
height:main.height
Loader
{
id:pageLoader
anchors.fill:parent
}
Image
{
id:backgroundImage
objectName: "background"
width:parent.width
height:parent.height
source: "Imgs/Images/NMS_NEW_4_TR_03.png"
LeftButtons
{
id: buttonKontrol
x: -20
y: 110
buttonName:"Kontrol"
MultiPointTouchArea
{
id:touchArea_kontrol
anchors.fill: parent
onPressed:
{
buttonKontrol.buttonImageColor="Imgs/Images/button_left_red.png"
buttonKontrol.buttonTextColor=textColorRed
pageLoader.source="KontrolPage.qml"
}
onReleased:
{
buttonKontrol.buttonImageColor="Imgs/Images/button_left_blue.png"
buttonKontrol.buttonTextColor=textColorBlue
}
}
}
LeftButtons
{
id:buttonKullaniciKitabi
x:-20
y:310
buttonName:"Kullanıcı Kitabı"
MultiPointTouchArea
{
id:touchArea_kullaniciKitabi
anchors.fill: parent
onPressed:
{
buttonKullaniciKitabi.buttonImageColor="Imgs/Images/button_left_red.png"
buttonKullaniciKitabi.buttonTextColor=textColorRed
}
onReleased:
{
buttonKullaniciKitabi.buttonImageColor="Imgs/Images/button_left_blue.png"
buttonKullaniciKitabi.buttonTextColor=textColorBlue
}
}
}
LeftButtons
{
id: buttonAyarlar
x:-20
y:510
buttonName: "Ayarlar"
MultiPointTouchArea
{
id:touchArea_ayarlar
anchors.fill: parent
onPressed:
{
buttonAyarlar.buttonImageColor="Imgs/Images/button_left_red.png"
buttonAyarlar.buttonTextColor=textColorRed
}
onReleased:
{
buttonAyarlar.buttonImageColor="Imgs/Images/button_left_blue.png"
buttonAyarlar.buttonTextColor=textColorBlue
}
}
}
RightButtons
{
id:buttonCCTV
x:1050
y:110
buttonName: "CCTV"
MultiPointTouchArea
{
id:touchArea_CCTV
anchors.fill: parent
onPressed:
{
buttonCCTV.buttonImageColor="Imgs/Images/button_right_red.png"
buttonCCTV.buttonTextColor=textColorRed
}
onReleased:
{
buttonCCTV.buttonImageColor="Imgs/Images/button_right_blue.png"
buttonCCTV.buttonTextColor=textColorBlue
}
}
}
RightButtons
{
id:buttonCTIS
x:1050
y:310
buttonName: "CTIS"
MultiPointTouchArea
{
id:touchArea_CTIS
anchors.fill: parent
onPressed:
{
buttonCTIS.buttonImageColor="Imgs/Images/button_right_red.png"
buttonCTIS.buttonTextColor=textColorRed
}
onReleased:
{
buttonCTIS.buttonImageColor="Imgs/Images/button_right_blue.png"
buttonCTIS.buttonTextColor=textColorBlue
}
}
}
RightButtons
{
id:buttonSisHavani
x:1050
y:510
buttonName: "Sis Havanı"
MultiPointTouchArea
{
id:touchArea_sisHavani
anchors.fill: parent
onPressed:
{
buttonSisHavani.buttonImageColor="Imgs/Images/button_right_red.png"
buttonSisHavani.buttonTextColor=textColorRed
}
onReleased:
{
buttonSisHavani.buttonImageColor="Imgs/Images/button_right_blue.png"
buttonSisHavani.buttonTextColor=textColorBlue
}
}
}
}
}
}

Related

How to use Qt MediaDevices type to switch AudioOutput device

I think I'm missing something here, but I can't figure out how to set a AudioOutput device from MediaDevices audioOutputs list with the QML Components
audioOutput: AudioOutput {
id: playerOutput
device: mediaDevices.defaultAudioOutput
onDeviceChanged: {
console.log("Output device changed " + device)
}
Component.onCompleted: {
console.log(mediaDevices.audioOutputs)
}
}
MediaDevices {
id: mediaDevices
}
The 2 devices are showing:
QAudioDevice(2, Built in earpiece (IN2023), false, Output),
QAudioDevice(3, Built in speaker (IN2023), false, Output)
but I don't understand how to change it, I've tried playerOutput.setDevice() description and id but it wants a QAudioDevice (it only provides description, id and mode, the documentation for both is very vague:
This property can be used to select an output device from the
QtMultimedia::MediaDevices::audioOutputs() list.
https://doc.qt.io/qt-6/qml-qtmultimedia-mediadevices.html
https://doc.qt.io/qt-6/qml-qtmultimedia-audiooutput.html#device-prop
Any help would be appreciated!
Thanks
You can assign an object from mediaDevices.audioOutputs to the devices property of your AudioOutput.
playerOutput.device = mediaDevices.audioOutputs[index]
where index is a valid index in the audioOutputs list.
import QtQuick
import QtQuick.Window
import QtMultimedia
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello AudioOutput")
MediaDevices {
id: mediaDevices
}
MediaPlayer {
id: mediaPlayer
source: "qrc:/Test_ogg_mp3_48kbps.wav"
audioOutput: AudioOutput {
id: playerOutput
device: mediaDevices.defaultAudioOutput
onDeviceChanged: { console.log("Output device changed " + device) }
Component.onCompleted: { console.log(mediaDevices.audioOutputs) }
}
}
component MediaPlayerButton : Rectangle {
id: button
property alias text: label.text
property bool active: false
signal clicked
width: 100; height: 40; radius: 10
color: button.active ? "tomato" : "ghostwhite"
border.color: "gainsboro"
border.width: buttonMouseArea.containsMouse ? 4 : 2
Text {
id: label
anchors.centerIn: parent
font.pointSize: 18
}
MouseArea {
id: buttonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: button.clicked()
}
}
Column {
spacing: 10
anchors.centerIn: parent
Row {
spacing: 10
MediaPlayerButton {
text: qsTr("Play")
active: mediaPlayer.playbackState === MediaPlayer.PlayingState
onClicked: { mediaPlayer.play() }
}
MediaPlayerButton {
text: qsTr("Pause")
active: mediaPlayer.playbackState === MediaPlayer.PausedState
onClicked: { mediaPlayer.pause() }
}
MediaPlayerButton {
text: qsTr("Stop")
active: mediaPlayer.playbackState === MediaPlayer.StoppedState
onClicked: { mediaPlayer.stop() }
}
}
Repeater {
model: mediaDevices.audioOutputs
Row {
spacing: 10
Rectangle {
id: r
width: 40; height: 40; radius: 20
color: mediaPlayer.audioOutput.device === mediaDevices.audioOutputs[index] ? "tomato" : "ghostwhite"
border.color: "gainsboro"
border.width: jackMouseArea.containsMouse ? 4 : 1
MouseArea {
id: jackMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: playerOutput.device = mediaDevices.audioOutputs[index]
}
}
Text {
anchors.verticalCenter: r.verticalCenter
font.pointSize: 12
text: mediaDevices.audioOutputs[index].description
}
}
}
}
}

Choreography in qml

Is there possible to use choreography animations in qml (in a REUSABLE manner)?
for example in StackView transitions from page1 to page2.
I tried following code, but ParentChange does not work as expected. This code just changes red rectangle's position.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
StackView {
id: stack
anchors.fill: parent
initialItem: Page {
id: page1
Label {
text: qsTr("First page")
anchors.centerIn: parent
}
Rectangle {
id: rect
width: 50
height: 50
x: 600
y: 100
color: "red"
states: [
State {
when: stack.depth > 1
ParentChange { target: rect; parent: stack.currentItem; x: 100; y: 100; }
}
]
transitions: Transition {
ParentAnimation {
NumberAnimation { properties: "x,y"; duration: 1000 }
}
}
}
MouseArea {
anchors.fill: parent
onClicked: stack.push(page2)
}
}
Component {
id: page2
Page {
background: Rectangle { color: "yellow"; anchors.fill: parent }
Label {
text: qsTr("Second page")
anchors.centerIn: parent
}
}
}
}
Rectangle {
id: back
color: "blue"
width: 50
height: 50
radius: 25
MouseArea {
anchors.fill: parent
onClicked: stack.pop()
}
}
}
but the usage is not limited to StackView. It can be used in many other situations. (just like above link)

How to propertly connect signal in Loader's item?

I want connect one signal from QObject to various pages, loaded by the "Loader" qml element. My problem similar Dead QML elements receiving signals? but loaded items destroyed before calling the "onDestruction" method.
For example below, if switch from page1 to page2 in console writed:
"QML: Loading status: 1 Item: QDeclarativeRectangle(0x8dcd408, "page2")
QML Item: Loaded QDeclarativeRectangle(0x8dcd408, "page2") 1
qrc:/page1.qml:12: TypeError: Result of expression 'parent' [null] is not an object.
qrc:/page1.qml:15: ReferenceError: Can't find variable: page1text"
every second. So there can't disconnect from signal because parent object is destroyed.
How to handle signals from QObject (root) in loaded items? or How to disconnect signal from unloaded page?
main.qml
import QtQuick 1.1
Rectangle {
id: root
objectName: "root"
width: 360
height: 360
state: "page1"
color: "white"
Item {
width: parent.width
height: parent.height/2
anchors.top: parent.top
Loader {
id: pageLoader
objectName: "pageLoader"
anchors.fill: parent
anchors.centerIn: parent
signal textMsg(variant params)
onStatusChanged: console.log("QML: Loading status: ", status, " Item: ", item)
onLoaded: { console.log("QML Item: Loaded",item,status); }
}
}
states: [
State {
name: "page1"
PropertyChanges { target: pageLoader; source: "qrc:/page1.qml"}
}
,State {
name: "page2"
PropertyChanges { target: pageLoader; source: "qrc:/page2.qml"}
}
]
Timer {
// simulate signals from QObject
interval: 1000; running: true; repeat: true
onTriggered: pageLoader.textMsg({"msg2page1":"test","msg2page2":"test"})
}
Rectangle {
anchors.left: parent.left
anchors.bottom: parent.bottom
width: parent.width/2
height: parent.height/2
border {
color: "black"
width: 1
}
color: "yellow"
Text{
anchors.fill: parent
anchors.centerIn: parent
text: "Set Page 1"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.state = "page1";
}
}
}
Rectangle {
anchors.right: parent.right
anchors.bottom: parent.bottom
width: parent.width/2
height: parent.height/2
border {
color: "black"
width: 1
}
color: "red"
Text{
anchors.fill: parent
anchors.centerIn: parent
text: "Set Page 2"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.state = "page2";
}
}
}
}
page1.qml
import QtQuick 1.1
Rectangle {
id: page1
objectName: "page1"
color: "yellow"
Component.onCompleted: {
parent.textMsg.connect(msgHandler);
}
Component.onDestruction: {
parent.textMsg.disconnect(msgHandler);
}
function msgHandler(params) {
page1text.text += " "+params.msg2page1;
}
Text {
id: page1text
anchors.fill: parent
wrapMode: Text.WordWrap
text: "page1"
}
}
page2.qml
import QtQuick 1.1
Rectangle {
id: page2
objectName: "page2"
color: "red"
}
That's nicely described in Loader documenation. It reads:
Any signals emitted from the loaded item can be received using the Connections element.
There is also an example, I copy it below for the sake of clarity:
// Application.qml
import QtQuick 1.0
Item {
width: 100; height: 100
Loader {
id: myLoader
source: "MyItem.qml"
}
Connections {
target: myLoader.item
onMessage: console.log(msg)
}
}
// MyItem.qml
import QtQuick 1.0
Rectangle {
id: myItem
signal message(string msg)
width: 100; height: 100
MouseArea {
anchors.fill: parent
onClicked: myItem.message("clicked!")
}
}
Clearly, if item is destroyed, any signal handlers are ignored until the target is recreated again.
My answer is: Don't use the "Loader", create child object by JS and destroy it as no needed, for example:
main.qml
import QtQuick 1.1
import "qrc:/pageloader.js" as Pageloader
Rectangle {
id: root
objectName: "root"
width: 360
height: 360
state: "page1"
color: "white"
signal textMsg (variant params)
states: [
State {
name: "page1"
StateChangeScript{ script: Pageloader.createPageObject("qrc:/page1.qml");}
}
,State {
name: "page2"
StateChangeScript{ script: Pageloader.createPageObject("qrc:/page2.qml");}
}
]
Timer {
// simulate signals from QObject
interval: 1000; running: true; repeat: true
onTriggered: textMsg({"msg2page1":"test","msg2page2":"test"})
}
Rectangle {
anchors.left: parent.left
anchors.bottom: parent.bottom
width: parent.width/2
height: parent.height/2
border {
color: "black"
width: 1
}
color: "yellow"
Text{
anchors.fill: parent
anchors.centerIn: parent
text: "Set Page 1"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.state = "page1";
}
}
}
Rectangle {
anchors.right: parent.right
anchors.bottom: parent.bottom
width: parent.width/2
height: parent.height/2
border {
color: "black"
width: 1
}
color: "red"
Text{
anchors.fill: parent
anchors.centerIn: parent
text: "Set Page 2"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.state = "page2";
}
}
}
}
pageloader.js
var component;
var sprite;
function createPageObject(path) {
if(sprite){
console.log("sprite.destroy() ",typeof sprite);
sprite.destroy();
console.log("component.destroy() ",typeof component);
component.destroy();
}
component = Qt.createComponent(path);
if (component.status === Component.Ready)
finishCreation();
else
component.statusChanged.connect(finishCreation);
}
function finishCreation() {
if (component.status == Component.Ready) {
sprite = component.createObject(root);
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
} else{
if (component.status === Component.Error) {
// Error Handling
console.log("Error loading component:", component.errorString());
}else{
console.log("Component status changed:", component.status);
}
}
}
page1.qml and page2.qml not changed.
I got it. My setup:
qml file to display ListViews
Several qml files defining Listviews, each takes a different column of different SQL tables. The model comes from C++
So here is the shortened code:
Dialog {
id: dialog
width: 1000; height: 400
property Component listViewItem
signal newDatabaseEntry( string text ) [1]
contentItem: Rectangle {
[...]
TextInputWithButton { [3]
id: newRecords
onInputAccepted: { newDatabaseEntry( text ) } [1]
}
}
[...]
Loader {
id: listViewPlaceholder
anchors.fill: parent
sourceComponent: dialog.listViewItem
onLoaded: {
if( typeof listViewPlaceholder.item.insertRecord === "function" )
// newRecords.inputAccepted.connect( listViewPlaceholder.item.insertRecord ) [1]
dialog.newDatabaseEntry.connect( listViewPlaceholder.item.insertRecord ) [2]
}
The above code is the general view of ListViews. The signal roundtrip [1] is necessary, otherwise no data is passed. How to chain signals is described here:
http://doc.qt.io/qt-5/qtqml-syntax-signals.html#connecting-signals-to-methods-and-signals
The input button [3] delivers the confirmed data to be inserted into the db.
A ListView passed to the above function looks like this:
DialogSqlSingleColumnEdit {
listViewItem: ListView {
function insertRecord( text ) {
console.log( "done:" + text )
sqlModel.insertRecord( text )
}
[...]
The insertRecord is called forwards the text to the sql-C++ model.

How to access the property of a GridView - or ListView - element

Here is the code, I create 4 buttons. When one is clicked I wanna that its color changes to red and the color of all the others change to black.
But looks like I could not access the color property.
Rectangle {
id: root
width: 200; height: 100
DelegateModel {
id: visualModel
model: ListModel {
ListElement { my_color: "red" }
ListElement { my_color: "black" }
ListElement { my_color: "black" }
ListElement { my_color: "black" }
}
groups: [
DelegateModelGroup { name: "selected" }
]
delegate: Rectangle {
id: item
height: 25
width: 200
color:my_color
MouseArea {
anchors.fill: parent
onClicked: {
console.log(visualModel.items.get(index).color)
for (var i = 0; i < root.count; i++){
if(index == i)
visualModel.items.get(i).color = "red";
else
visualModel.items.get(i).color = "black";
}
}
}
}
}
ListView {
anchors.fill: parent
model: visualModel
}
}
I advice you to use ExclusiveGroup from QML controls. Usually it is used for Action but it's possible to use it for any other Item. From the Qt docs:
It is possible to add support for ExclusiveGroup for an object or
control. It should have a checked property, and either a
checkedChanged, toggled(), or toggled(bool) signal.
So all we need is to add suitable property. Small example:
import QtQuick 2.5
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
Window {
width: 200
height: 400
ExclusiveGroup { id: exclusiveGroup }
ListView {
anchors.fill: parent
anchors.margins: 5
spacing: 2
model: 10
delegate: Rectangle {
id: myItem
property bool checked: false // <-- this is necessary
height: 30
width: parent.width
color: myItem.checked ? "lightblue" : "#DEDEDE"
border { width: 1; color: "#999" }
radius: 5
Text { text: "item" + (index + 1); anchors.centerIn: parent}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: myItem.checked = !myItem.checked;
}
Component.onCompleted: {
exclusiveGroup.bindCheckable(myItem);
}
}
}
}

How to switch back between two windows in QML

I Create qml file like this :
main.qml
Item {
width: 200; height: 200
Loader { id: pageLoader }
MouseArea {
anchors.fill: parent
onClicked: pageLoader.source = "Page1.qml"
}
}
I want to back to main page from Page1.qml.
How I can do this Work?
just set the source of pageLoader in Page1 to nothing:
Main Page :
import QtQuick 1.0
Rectangle {
width: 360
height: 360
Text {
anchors.centerIn: parent
text: "Main Page"
}
MouseArea {
anchors.fill: parent
onClicked: {
ld.source="Test.qml"
}
}
Loader{
id:ld;
anchors.fill: parent;
}
}
Test.qml
Rectangle {
width: 100
height: 62
color: "navy";
Text {
anchors.centerIn: parent
text: "Page 1"
}
MouseArea{
anchors.fill: parent;
onClicked: ld.source="";
}
}
Don't you have to instanciate the loader once again in Test.qml to access it via var

Resources