0

I want to show ListView with model, that is QVector of custom class. This question pretty much the same Qt QML C++ QList of structs as custom ListView model , but solution doesnt work for me. Here is a class, that contain fields. Signals and write-read autogenerated.

class Subject : public QObject
{
    Q_OBJECT
public:
    int First;
    int Second;

    explicit Subject(int fFirst = 0, int fSecond = 0, QObject *parent = nullptr)
    {
        this->First = fFirst;
        this->Second = fSecond;
        emit FirstChanged();
        emit SecondChanged();
    }
    Subject::Subject(const Subject &Copy)
    {
    this->First = Copy.First;
    this->Second = Copy.Second;
    emit FirstChanged();
    emit SecondChanged();
    }
    void Subject::operator=(const Subject &Right)
    {
    this->First = Right.First;
    this->Second = Right.Second;
    }
    
private:
    Q_PROPERTY(int _First READ getFirst WRITE setFirst  NOTIFY FirstChanged FINAL)
    Q_PROPERTY(int _Second READ getSecond WRITE setSecond NOTIFY SecondChanged FINAL)
};

Here is a controller class

class Controller : public QObject
{
    Q_OBJECT
public:
    explicit Controller(QObject *parent = nullptr)
    {
        this->List.push_back(Subject(1, 0));
        this->List.push_back(Subject(2, 0));
    }
    QVector<Subject> List;
    QVector<Subject> getList() const;
    void setList(const QVector<Subject> &newList);

    Q_INVOKABLE void printAll();
private:
    Q_PROPERTY(QVector<Subject> _List READ getList CONSTANT)
};

Qml main is Window with this

    Controller
    {
        id: _Controller
        Component.onCompleted:
        {
            _Controller.printAll()
        }
    }
    ListView
    {
        anchors.fill: parent
        model: _Controller._List
        Component.onCompleted:
        {
            for (let i = 0; i < 2; i++)
            {
                console.log(_Controller._List[0])
            }
        }
        delegate: Text {
            id: _delegated
            text: qsTr(modelData._First)
            font.bold: true
            color: "black"
            font.pointSize: 24
        }
    }

I pretty much followed the solution, but i got nothing on my screen. The "List" is not empty on completed. Tried to change it to not const and emit ListChanged after app is running, but text not appearing. When I try to iterate through vector on ListView completed, like this

Component.onCompleted:
        {
            for (let i = 0; i < 2; i++)
            {
                console.log(_Controller._List)
            }
        }

Im getting this

qml: QVariant(QList<Subject>, )
qml: QVariant(QList<Subject>, )
5
  • I tried to make question as compact as possible, but the text still gigantic Commented Jun 2, 2024 at 0:35
  • 1
    Have you also registered "Subject" class? Moreover, why not just use a QAbstractListModel? Commented Jun 3, 2024 at 15:06
  • @morteza Yes, I did registered it. Thanks for advice about QAbstractListModel, didnt know about it. But if I did - I'd probably didnt want to complicate application with another class, if I could achieve same result without it. Commented Jun 3, 2024 at 16:03
  • 1
    I see a whole bunch of different violations here. emitting a signal from constructor? An object still doesn't exist in this case. a private property? what a sense in that? Commented Jun 3, 2024 at 18:26
  • @folibis Im aware, that emiting in constructor doesnt do much, IDE says the same, but I was desperate, so tried anything. And private property - that the was IDE generate them and it works fine. Commented Jun 6, 2024 at 4:49

1 Answer 1

1

There are a few bugs in your code. But with the following change as Accessing C++ QLists from QML suggested, the problem will be solved (Tested).

#include "subject.h"

class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(QVector<Subject*> _List READ getList CONSTANT)

public:
explicit Controller(QObject *parent = nullptr){
    this->List.push_back(new Subject(1, 0));
    this->List.push_back(new Subject(2, 0));
}
QVector<Subject*> List;
QVector<Subject*> getList() const{
    return this->List;
}
};

The main takeaway is changing

QVector<Subject> _List

to

QVector<Subject*> _List

and some other changes that follows. Moreover, "Subject" and "Controller" class should be registered before loading the QML engine. Something like this:

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<Controller>("Controller",1,0,"Controller");
    qmlRegisterUncreatableType<Subject>("Subject",1,0,"Subject","Reference only");

    QQmlApplicationEngine engine;
    QObject::connect(&engine,engine.objectCreationFailed,&app,[&app](){app.exit(-1);});
    engine.loadFromModule("Main","Main");
    return app.exec();
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for reply, yes, it seems to fix the issue, but it also requires to convert value of modelData._First to string, so property int value: modelData.first required before using it in text.
@VoiceShifter Sure. If you insist on using qsTr.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.