Update Text inside loaded qml file - qt

We are having an ApplicationWindow based main.qml which is connected to our python backend via QmlElement Bridge. We have a view Slot-methods which directly return values to the qml frontend to change textfields which are children of the ApplicationWindow like the following:
ApplicationWindow {
id: mainFrame
width: 1280
height: 720
visible: true
title: qsTr("Test")
StackView {
id: stack
initialItem: loginFrame
anchors.fill: parent
}
Bridge {
id: bridge
}
Component{
id: loginFrame
ColumnLayout {
anchors.margins: 3
spacing: 3
Layout.columnSpan: 1
Layout.alignment: Qt.AlignHCenter
Text {
id: title
Layout.alignment: Qt.AlignHCenter
font.pointSize: 16
text: "Login Screen"
Layout.preferredHeight: 100
}
Button {
id: loginButton
Layout.alignment: Qt.AlignHCenter
text: "login"
highlighted: true
Material.accent: Material.Red
onClicked: {
title.text = bridge.login(username.text, password.text)
}
}
}
}
}
To reduce the size of our main.qml we decided to load the other Layouts, Components etc from different files with
Loader {
id: otherLoader
source: "other.qml"
}
How to access the Text Object inside of other.qml to update the text property from main.qml because the value is provided by the Bridge?
I already tried Accessing TextField from Another QML File but this hasn't worked.

The Loader creates items in not the same context as the statically create item use so cannot access the loaded item. You have several ways to access such an item.
The first and the most correct way is to use a declarative style:
Item {
id: container
anchors.fill: parent
property string someText: "press again"
Loader {
id: loader
active: false
sourceComponent: Text {
id: txt
text: container.someText
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if(loader.active)
container.someText = "some text"
else
loader.active = true
}
}
}
You can create a binding in a Javascript code whenever you want:
Loader {
id: loader
active: false
sourceComponent: Text {
id: txt
Component.onCompleted: {
txt.text = Qt.binding(function() { return container.someText; })
}
}
}
Another option is using Loader.item property:
Item {
id: container
anchors.fill: parent
property string someText: "some text"
Loader {
id: loader
active: false
sourceComponent: Text {
id: txt
text: "press again"
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if(loader.active)
loader.item.text = "some text"
else
loader.active = true
}
}
}

Related

How to properly popup and resize Dialog from another .qml file

Learning qml and trying to separate main window and settings in different files. I have a SettingsView.qml with simple Dialog and Have a main.qml where I call menu and call my settings dialog to popup. When I had a Dialog in main.qml it was fine and it had been resizing with whole window properly. But after I had moved it to different file the behaviour changed. Now also I recieve a message: "refSettingsDialog is not defined". I would be gratefull for any advices.
upd: Closed. No need in properties here etc just basics. And do not call id from another file. Atleast, as I understand it by now
SettingsView.qml
Dialog{
id: settingsDialog
modal: true
focus: true
title: "Settings"
standardButtons: Dialog.Ok | Dialog.Cancel
onAccepted: {
settingsDialog.close()
}
onRejected: {
settingsDialog.close()
}
}
main.qml
ApplicationWindow {
visible: true
id: screen
property alias mainScreen: screen
width: 640
height: 480
property alias screenWidth: screen.width
property alias screenHeight: screen.height
title: qsTr("McdtViewer")
Material.theme: Material.Dark
Material.accent: Material.Yellow
SystemPalette { id: activePalette }
//toolbar
header: ToolBar {
RowLayout {
spacing: 20
anchors.fill: parent
ToolButton {
icon.name: contentSwiper.currentIndex === 1 ? "Back" : "пустой"
onClicked: {
if (contentSwiper.currentIndex === 1){
contentSwiper.pop()
}
}
}
Label {
id: titleLabel
text: contentSwiper.currentIndex === 0? "ExpWatcher": "ExpView"
font.pixelSize: 20
elide: Label.ElideRight
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
Layout.fillWidth: true
}
ToolButton {
icon.name: "menu"
onClicked: optionsMenu.open()
Menu {
id: optionsMenu
x: parent.width - width
transformOrigin: Menu.TopRight
MenuItem {
text: "Settings"
//calling the instance of settingView which we declared in the bottom
onTriggered: {
settingsView.open()
}
}
}
}
}
}
}
// making instance of settingsDialog here so the width will be calculated properly.
SettingsView{
id: settingsView
x: Math.round((screenWidth - width) / 2)
y: Math.round(screenHeight / 6)
width: Math.round(Math.min(screenWidth, screenHeight) / 3 * 2)
}
}

QML reset dialog with tabview

I was trying to implement a tabbed Dialog in QML with the means to reset it to the intial values.
Since tabs are dynamically instantiated, none of the straight forward methods seem to work. The parent Dialog can not reference the inner Combobox and the Combobox can not reference the outer Dialog. How can this be achieved?
import QtQuick 2.3
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
Dialog {
id: dlg
title: "Settings"
visible: true
standardButtons: StandardButton.Apply | StandardButton.Reset
property string val: ""
onApply: console.log(val)
onReset: {
// RESET COMBOBOX TO DEFAULT
}
TabView {
id: tabView
anchors.fill: parent
Tab {
title: "ValueTab"
id: tabVal
GridLayout {
id: gridVal
anchors.fill: parent
GroupBox {
title: qsTr("Choose value")
id: gb
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
id: cl
ComboBox {
id: valueChooser
editable: false
model: ListModel {
id: listModel
ListElement { text: "One" }
ListElement { text: "Two" }
ListElement { text: "Three" }
}
Layout.fillWidth: true
onCurrentTextChanged : val = currentText
}
}
}
}
}
}
}
I am quite unsure, if I got your question right as you say, you can not reference the Dialog from within the Combobox. I can not see the reason why.
Assuming the example of yours contains indeed your problem and all you want to do is to reset the values (and you know the original values) once the reset button is pressed, this is how I would solve it.
Using the Connections-type to connect to the Dialog's reset() from within the Combobox
import QtQuick 2.3
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.1
Dialog {
id: dlg
title: "Settings"
visible: true
standardButtons: StandardButton.Apply | StandardButton.Reset
property string val: ""
onApply: console.log(val)
onReset: {
// **DONT** RESET COMBOBOX TO DEFAULT **HERE**
}
TabView {
id: tabView
anchors.fill: parent
Tab {
title: "ValueTab"
id: tabVal
GridLayout {
id: gridVal
anchors.fill: parent
GroupBox {
title: qsTr("Choose value")
id: gb
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
id: cl
ComboBox {
id: valueChooser
editable: false
model: ListModel {
id: listModel
ListElement { text: "One" }
ListElement { text: "Two" }
ListElement { text: "Three" }
}
Layout.fillWidth: true
onCurrentTextChanged : val = currentText
/// *** INTERESTING PART HERE! ***
Connections {
target: dlg
onReset: {
// RESET COMBOBOX TO DEFAULT **HERE** INSTEAD
valueChooser.currentIndex = 0
}
}
}
}
}
}
}
}
}

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();
}
}

QtQuick TableView delete row doesn't work

I am using QtQuick TableView to show data from a database through QSqlTableModel and QSortFilterProxyModel.
The remove row operation doesn't work as it should. I have implemented a method in a class derived from QSortFilterProxyModel to call removeRows methods of QSortFilterProxyModel.
Everything works correctly as long as I have a filter setted in QSortFilterProxyModel ( i set it through a text box ). But when the filter is empty, the TableView rowCount property doesn't decrement and, after each delete, the currentRow property is set to rowCount-2. Why? To me it looks like a bug. Why it works when the filter is not empty?
Q_INVOKABLE void eliminaCliente(int row) {
removeRows(row,1);
}
import QtQuick 2.6
import QtQuick.Controls 1.5
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2
import Material 0.2
import Material.ListItems 0.1
ApplicationWindow {
id: root
visible: true
width: 1024
height: 640
title: qsTr("assiBase")
Page {
id: pLayout
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
Toolbar {
id: aBar
Layout.fillWidth: true
page: pLayout
backgroundColor: "#eeeeee"
RowLayout {
anchors.fill: parent
ActionButton {
id: addButton
Layout.leftMargin: 10
iconName: "content/add_circle"
backgroundColor: "#4CAF50"
onClicked: modalDialog.show()
isMiniSize: true
}
ActionButton {
id: editButton
iconName: "content/create"
isMiniSize: true
}
ActionButton {
id: deleteButton
iconName: "action/delete"
isMiniSize: true
backgroundColor: "#FF0000"
onClicked: {
if (dataView.currentRow != -1) {
var r = dataView.currentRow
console.log(dataView.currentRow)
sqlSortedData.eliminaCliente(dataView.currentRow)
console.log(dataView.rowCount)
//dataView.currentRow = r
}
}
}
RowLayout {
Layout.alignment: Qt.AlignRight
Icon {
name: "action/search"
Layout.alignment: Qt.AlignBottom
}
TextField {
id: searchBox
Layout.rightMargin: 20
Layout.minimumWidth: 400
Layout.preferredWidth: 500
placeholderText: qsTr("cerca...")
onTextChanged: sqlSortedData.setFilterWildcard(searchBox.text)
font.capitalization: Font.MixedCase
}
}
}
}
TableView {
anchors.top: aBar.bottom
anchors.topMargin: 3
sortIndicatorVisible: true
frameVisible: false
Layout.fillWidth: true
Layout.fillHeight: true
onSortIndicatorColumnChanged: model.sort(sortIndicatorColumn, sortIndicatorOrder)
onSortIndicatorOrderChanged: model.sort(sortIndicatorColumn, sortIndicatorOrder)
id: dataView
TableViewColumn {
role: "ID"
visible: false
}
TableViewColumn {
role: "Nome"
title: "Nome"
width: 200
}
TableViewColumn {
role: "Residenza"
title: "Residenza"
width: 200
}
TableViewColumn {
role: "Assicurazione"
title: "Assicurazione"
width: 200
}
TableViewColumn {
width: 128
resizable: false
delegate: RowLayout {
anchors.fill: parent
clip: true
IconButton {
iconName: "content/create"
onClicked: console.log(styleData.row)
}
IconButton {
iconName: "action/delete"
onClicked: {
console.log(styleData.row)
sqlSortedData.eliminaCliente(styleData.row)
console.log(dataView.rowCount)
}
}
}
}
model: sqlSortedData
}
}
}
Take a look at here. There is an workaround suggestion.
It seems like QSortFilterProxyModel needs some love for a long time.

TableView not the correct size with QML

I am trying to create a TableView with QML where I have a checkbox, an image and a text field. The table column definitions are as follows:
// TableViewCheckBoxColumn.qml
TableViewColumn {
title: ""
role: "check"
delegate: CheckBox {
anchors.fill: parent
checked: styleData.value
}
}
//TableViewImageColumn.qml
TableViewColumn {
title: ""
role: "thumbnail"
delegate: Image {
anchors.fill: parent
source: styleData.value
width: 30
height: 30
}
}
Now the data model and the table itself is defined as a QML component as follows:
Item {
ListModel {
id: sourceModel
ListElement {
check: false
thumbnail: "file:///Users/xargon/alignment.png"
length: "10:22"
}
}
// Table view
TableView {
anchors.centerIn: parent
alternatingRowColors: false
TableViewCheckBoxColumn {
id: checkedColumn
}
TableViewImageColumn {
id: thumbColumn
}
TableViewColumn {
id: lengthColumn
role: "length"
title: "Length"
}
model: sourceModel
}
}
Now, this is embedded in a ColumnLayout and a StackView as:
ColumnLayout {
anchors.fill: parent
MyTable {
id: reviewScreen
Layout.fillWidth: true
}
StackView {
id: options
Layout.fillHeight: true
Layout.fillWidth: true
initialItem: reviewScreen
}
}
Now I was expecting the table to fill the entire width of the parent control and I also was expecting the image to be drawn as a 30 x 30 image but what I see is the attached screenshot where the horizontal scrollbar is there to move between controls and the table is small and the image is very distorted as well.
yes, only you need declare heigh and weight of every TableViewColumn, for example:
TableViewColumn { id: lengthColumn; role: "length"; title: "Length"; height: parent.height/8; width:parent.width*0.25}

Resources