how to trigger a c++ function in qml - qt

I have one more question in connection with my QVariantMap. Currently I trigger the filling directly at startup (c++):
StyleConfiguration::StyleConfiguration(QObject *parent) : QObject(parent)
{
restore("q_button");
}
However, I would like to have the map filled directly at runtime in qlm, but don't know how to manage that.
Somethings like this:
xxxx: _styleconfiguration.restore("q_button")
Similar to a repeater:
Repeater{
model: _styleconfiguration.restore("q_button")
}
what should I use for xxx? Would be happy if someone can help me further.
addition:
mainWin.qml:
Rectangle {
id: dashboard
...
Row {
...
//----------------Button-------------//
Grid {
....
Component.onCompleted: _styleconfiguration.readValue("q_button") // **<- Call to read out the json**
Repeater {
id: dashboardButtons
model: _configuration.buttonMapping
Q_Button{ // **<- use read out values from the json**
id: dashButton
text: dashboard.functionsDashboard[modelData].text
...
}
}
}
}
//----------------Longpress Menu-------------//
Popup {
...
contentItem: Rectangle {
...
Column {
....
Component.onCompleted: _styleconfiguration.readValue("l_button")
Repeater {
model: dashboard.functionsDashboard
L_Button {
text: modelData.text.replace('\n', ' ')
....
}
}
}
}
}
}
}
Q_Button.qml:
Rectangle {
id: button
width: _styleconfiguration.styleMapping["width"]
height: _styleconfiguration.styleMapping["height"]
...
}
I hope the addition helps for understanding

I'm not sure I understand your question completely...
You have to mark your method declaration as Q_INVOKABLE in order to call it from QML:
Q_INVOKABLE void restore(const QString& s);
Then you can call it at creation of your QML Component.
Component.onCompleted: _styleconfiguration.restore("q_button")

Related

How to store the data of a nested ListView and retrieve after , without a listmodel in qml

I have 3 nested ListViews.The first is the month, second is day and third is hour of day.All of them constructs a calendar.There is a loader that loads a window when I click in the hour ListView, and set text in a Label.This text can be displayed in the hour view and can be deleted or edited through the above window .Unfortunately the text can not be saved because when I scroll the ListViews, delegates changing and not keeping the context of the label(That is normal I suppose).The objective is to be able to save those texts in the label(store the data) and restore them when the application is closed and re-opened.
Below is a generic code sample for 3 ListViews:
ApplicationWindow{
id:appwindow
............
Item{
id:dayView
...........
ListView{
id:monthofdayCalendar
orientation:Qt.Horizontal
model:12
delegate: Item{
ListView{
id:dayCalendar
orientation: Qt.Horizontal
model:32
delegate: Item{
...............
ListView{
id:daylistView
orientation: Qt.Vertical
model:24
delegate:Item{
id:hourItem
property string hourTime:hourweeklistviewLabel
property string notetaking:notesLabe
.............
MouseArea{
anchors.fill:parent
onClicked:{
windowLoader.active =true
daylistView.currentIndex=index
}
}
Rectangle{}
Label{
id:hourweeklistviewLabel
}
Label{
id:notesLabel
anchors.left:hourweeklistviewLabel.right
anchors.leftMargin: 30
text:""
}//Label
}//delegate:Item
}//ListView
} //delegate:Item
}//ListView
}//delegate:Item
}//Listview
}//Item
Below is the code of loader:
Loader {
id:windowLoader
focus: true
active:false
sourceComponent: Window{
id:inputWin
title:"Enter Note"
width:500
height:300
visible:true
onClosing:{
windowLoader.active=false
monthofdayCalendar.currentItem.daycalendarAlias.currentItem.dayList.currentIndex = calendarMonth.selectedDate.getDate() === new Date().getDate()
&& calendarMonth.selectedDate.getDay() === new Date().getDay()
&& calendarMonth.selectedDate.getMonth() === new Date().getMonth()?getHour():12
}
TextField {
id:title
x:50
y:20
placeholderText :'Enter Note'
text:monthofdayCalendar.currentItem.daycalendarAlias.currentItem.dayList.currentItem.notetaking.text
}
TextField{
id:timeDate
anchors.horizontalCenter: title.horizontalCenter
anchors.top:title.bottom
anchors.topMargin:10
placeholderText : calendarMonth.selectedDate.getDate() +"-"
+ (calendarMonth.selectedDate.getMonth()+1)+"-"
+ calendarMonth.selectedDate.getFullYear() + " "
+ monthofdayCalendar.currentItem.daycalendarAlias.currentItem.dayList.currentItem.hourTime.text
}
Button {
id: button
text: qsTr("Add Note")
anchors.centerIn:parent
onClicked: {
if (title.text !==""){monthofdayCalendar.currentItem.daycalendarAlias.currentItem.dayList.currentItem.notetaking.text= title.text}
else{}
}
}
}
}
The big question is how to save (store) the data of notesLabel.text and be able to display it and restore it every time I close and re-open the application.
As you can see the model for each ListView is not a ListModel so I think I can not use those models to save the data if I am right.If I am wrong please advise.
Anyway your help will be appreciateed.
EDIT
I've changed the integer models with ListModel dynamically created.The code of the ListModels is below:
ListModel{
id:hourlistModel
Component.onCompleted:{
for (var i = 0; i <25; i++){
append(createListElement())
}
}
property int h:0
function createListElement(){
return {
hour : h++
}
}
}
ListModel{
id:daylistModel
Component.onCompleted:{
for (var j=0; j <= 31; j++){
append(createListElement())
}
}
property int dD:0
function createListElement(){
return {
day : dD++
}
}
}
ListModel{
id:monthlistModel
Component.onCompleted:{
for (var k=0; k <=11; k++){
append(createListElement())
}
}
property int mN:0
function createListElement(){
return {
monthName : mN++
}
}
}
Can I store the data from Label notesLabel, now I've changed the models of ListViews with ListModels?
Thanks in advance.
I would create an exposed C++ class.
Using the exposed C++ class you have a range of options to pass data from the front/backend
Q_Property/Member
Q_Invokable
Signal/Slots
Given that you are using strictly strings, I would use an exposed series of QStrings or a QStringList.
QString
QStringList
To tackle to file read/write use your now exposed C++ class. You can either stick to file I/O via standard c++ or QFile system.
Constructor - Read the .txt file and save the data to your property data.
Exchange data as needed updating either the QML or C++ property member
Deconstructor - save the property member data back to file.
Brief example code:
someQML.qml
Import MyExposedClass 1.0
Item {
MyExposedClass {
id: myExposedClassID
text: myExposedClassID
}
Text{
id: yearTextID
text: myExposedClassID.year
}
Text{
id: monthTextID
text: myExposedClassID.month
}
Text{
id: dayTextID
text: myExposedClassID.day
}
Button {
id: myButtonID
onButtonPressed {
var finalStr = yearTextID + monthTextID + dayTextID
// If you used a QMember of qstring lets say
myExposedClassID.saveFile = finalStr
// If you used a QInvokable
myExposedClassID.saveFile_INVOK(finalStr)
}
}
}
myClass.h
class myClass : public QObject {
Q_OBJECT
// Serial Dev
Q_PROPERTY(QString day READ getDay WRITE setDay NOTIFY dayChanged)
Q_PROPERTY(QString month READ ... WRITE ... NOTIFY ...)
Q_PROPERTY(QString year READ ... WRITE ... NOTIFY ...)
...
// On construction, read the text file and update the qproperty variables
//implement getters and setters for qproperties
// On deconstruction, write the properties to file
}
If you have issues with MVC and QStrings/QStringlist. You may have to look into QVariants or QAbstracts.
I find QML to be a risky hole to dive into. Its easy to add more and more functionality to a QML file. But if you try and redesign it or change up some logic, it can very quickly ruin the QML. Splitting the QML into a QML & C++ is a nice way to achieve modularity and control.

Issue while using qmlRegisterType in two qml files

I have a c++ class which is registered as a qmlRegisterType in my main.cpp as below:
qmlRegisterType<MyTestClass>("com.my.MyTestClass", 1, 0, "MyTestClass");
I am using this class in two QML files as below:
// MyMain.qml
Window {
width: 1280
height: 720
StackLayout {
anchors.fill: parent
currentIndex: 0
MyQml1 {}
MyQml2 {}
}
}
// MyQml1.qml
Item {
MyTestClass {
id: myTestClass1Obj
onTestSignal: {
console.log("This function is not getting called");
}
}
}
// MyQml2.qml
Item {
MyTestClass {
id: myTestClass2Obj
onTestSignal: {
console.log("This function is getting called");
}
}
}
In above code the function onTestSignal from MyQml2.qml is getting called but not of MyQml2.qml.
If I register MyTestClass as qmlRegisterSingletonType then it works with Connections.
What is causing the issue?

How to track the first launch visibility of an Item on app window

I am using Qt 5.9.3. I have a QML Item like so:
Item {
id: root
width : 400
height: 700
}
How do I track when the Item was first time visible on screen of my application window? onVisibilityChanged?
How do I do track the same for a MyQuickItem which is something like this:
// C++ definition
class MyQuickItem : public QQuickitem {
}
// QML side
MyQuickItem {
id: some_id
}
I guess the complete code suppose like:
ApplicationWindow{
visible: true
onVisibilityChanged: {
console.log("ApplicationWindow is ", visibility)
}
Component.onCompleted: {
console.log("ApplicationWindow is onCompleted")
}
Item {
id: root
width : 400
height: 700
onVisibleChanged: {
console.log("Item is ", visible)
}
Component.onCompleted: {
console.log("Item is onCompleted")
}
}
}
Obviously the onVisibilityChanged of ApplicationWindow will trigger when the visibility property is changed, so it triggers when you minimize and reshow the window. As you mention the first time visible, so I think you are looking for Component.onCompleted.

Can Repeater delegate in Qml be made to behave in a generic way to the given Items?

{New to Qml (quick 2.0 using Qt 5.1 beta) and learning}.
I wanted to know if such an idiom would be possible in Qml:
Below I have objLeftColumn which expects its children to expose a boolean m_bIsSelected and a MouseArea alias m_mouseProperty and uses them to make the collection of such children mutually exclusive, ie., only one of them can be in selected state. The followin works fine but I need to repeat it every time I want and specially if I wanted it for Row etc.
Column {
id: objLeftColumn
property int m_iLastButtonClicked: -1
property int m_iCurrentButtonClicked: -1
onM_iCurrentButtonClickedChanged: {
if(m_iLastButtonClicked != -1) {
objLeftColumn.children[m_iLastButtonClicked].m_bIsSelected = false
}
m_iLastButtonClicked = m_iCurrentButtonClicked
}
Repeater {
id: objLeftColumnRepeater
model: 5
delegate: ABCD {
id: objABCD
m_mouseProperty.onClicked: {
if(m_bIsSelected) {
objLeftColumn.m_iCurrentButtonClicked = index
}
else {
objLeftColumn.m_iLastButtonClicked = -1
objLeftColumn.m_iCurrentButtonClicked = -1
}
}
}
}
}
Can I write a generic objLeftColumn (in a separate qml file) that could arrange the given Items in Column while aslo dealing with exclusivity of their selection?
The idea is instead of giving the component to the delegate right there an then, I'll give it later and for each instantiation of the component (depending on numeric value of model above and below) the delegate: in Repeater should behave similarly.
eg., in psedo code:
in Exclusive.qml:
Column {
id: objLeftColumn
property int m_iLastButtonClicked: -1
property int m_iCurrentButtonClicked: -1
property alias m_delegate: objLeftColumnRepeater.delegate
onM_iCurrentButtonClickedChanged: {
if(m_iLastButtonClicked != -1) {
objLeftColumn.children[m_iLastButtonClicked].m_bIsSelected = false
}
m_iLastButtonClicked = m_iCurrentButtonClicked
}
Repeater {
id: objLeftColumnRepeater
model: 5
onItemAdded: {
//state of item can be manipulated but want to
//add behaviour to the item eg:
/*item {
m_mouseProperty.onClicked: {
//do something
}
}*/
}
}
}
in SomeOther.qml:
Exclusive {
model: 5
delegate: ABCD
}
Exclusive {
model: 9
delegate: DEFG
}
etc..So this way Column in Exclusive is more generic and can be called with any Item assigned to its delegate and will behave similarly. Is this possible in qml
This needs a bit of trickery to be solved, I can think of two ways:
Use the JS connect() function to manually create the connections. Something like this:
Repeater {
id: objLeftColumnRepeater
model: 5
onItemAdded: {
item.m_mouseProperty.onClicked.connect(function() {
console.log("Clicked!");
});
}
}
Wrap the delegate into an Item by using a Loader, and use aConnections element for the connection. Something like this:
property Component delegate
Repeater {
id: objLeftColumnRepeater
model: 5
delegate: Item {
Loader {
id: loader
sourceComponent: delegate
}
Connections {
target: loader.item.m_mouseProperty
onClicked: console.log("Clicked")
}
}

Why do I need `text: model.display.foo` instead of just `text: foo` when using a C++ QAbstractListModel?

I'm very new with Qt / QtQuick.
I have a simple form designed with Qt Designer which consists uniquely of a ListView.
Item {
// ...
ListView {
id: listView1
anchors.fill: parent
model: FooModel
delegate: Item {
// ...
Row {
id: row1
Text {
text: foo
// ...
}
}
}
}
}
This works perfectly fine with the following - either by copy-pasting it inline as model, or by letting qmlscene or Qt Designer notice the FooModel.qml contained in dummydata:
ListModel {
ListElement {
foo: "1"
}
ListElement {
foo: "2"
}
ListElement {
foo: "3"
}
ListElement {
foo: "4"
}
}
However, when I try to replace my dummy model with an actual C++ model that subclasses QAbstractListModel, I have to replace text: foo with text: model.display.foo in the delegate:
delegate: Item {
// ...
Row {
id: row1
Text {
text: model.display.foo // <=== See?
// ...
}
}
}
If I don't, Qt complains that
qrc:/MainForm.ui.qml:23: ReferenceError: foo is not defined
and nothing is displayed.
I set the model property like this, in my main.cpp:
FooListModel* flm= new FooListModel();
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("FooModel", flm);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
Why is this?
Also - assuming "it's a feature and not a bug" - having to change the text attribute means that I can no longer have my dummy data in QtDesigner or use inline models for prototyping; can I avoid this in any way?
Please find the MWE in question here on Github.
qrc:/MainForm.ui.qml:23: ReferenceError: foo is not defined
Means you have to define foo role in the FooListModel. For example,
class FooListModel : public QAbstractListModel
{
public:
enum FooListModelRoles
{
FooRole = Qt::UserRole + 1,
BarRole,
//...
}
QHash<int, QByteArray> roleNames() const //override
{
QHash<int, QByteArray> roleName;
roleName[FooRole] = "foo"; //define "foo" role for QML
roleName[BarRole] = "bar"; //define "bar" role for QML
return roleName;
}
//...
}
And delegates in QML can access foo role now.
Also - assuming "it's a feature and not a bug"
Yes, text: model.display.foo works fine because display is a pre-defined role in QAbstractItemModel.

Resources