i have a cpp struct which have so much fields
struct CloudMusicSongList{ ... };
and i want use it in qml in order input some infomation to it's instance, but i don't want to create a qobject derived class,and create a lot of qproperty ...
i seache in google and get this code snippt from this blog
class ListItem : public QObject
{
Q_OBJECT
public :
ListItem(QObject *parent = 0) : QObject(parent) {}
virtual ~ListItem() {}
virtual int id() const = 0;
virtual QVariant data(int role) const = 0;
virtual QHash<int, QByteArray> roleNames() const = 0;
virtual void triggerItemUpdate() {emit dataChanged();}
signals:
void dataChanged();
};
i just try following code but even not print called data method
defined.h
template <typename T>
class bindingProxy : public bindingProxyBase
{
public:
bindingProxy(QObject* parent = 0)
: bindingProxyBase(parent)
{
}
T tm;
virtual ~bindingProxy()
{
}
virtual QVariant data(int role)
{
qDebug() << "called data method";
QVariant qv;
auto fucs = Prism::Reflection::get_md<T>();
if (role == Qt::DisplayRole)
fucs[0].getFunc(tm, 0, qv);
else
fucs[role].getFunc(tm, role, qv);
return qv;
}
QHash<int, QByteArray> roleNames() const
{
static QHash<int, QByteArray> roles{};
if (roles.count() == 0)
{
for (Prism::Reflection::PrismMetaData<T>& item : Prism::Reflection::get_md<T>())
{
roles[item.offset] = item.name;
}
}
return roles;
}
bool setData(QVariant& value, int role = Qt::EditRole)
{
Prism::Reflection::get_md<T>()[role].setFunc(tm, role, value);
triggerItemUpdate();
return true;
}
};
bodyViewModel.cpp
#include ....
...
..
Q_DECLARE_METATYPE(bindingProxy<CloudMusicSongList>*);
class BodyViewModel : public QObject
{
Q_PROPERTY(bindingProxy<CloudMusicSongList>* editSongListModel READ editSongListModel WRITE setEditSongListModel NOTIFY editSongListModelChanged)
...
...
...
uing.qml
Button {
id:btn_tst
text: BodyViewModelCpp.editSongListModel.name + "hbb"
onClicked: BodyViewModelCpp.editSongListModel.name = "3232"
}
button look like this image after run app rung
i don't know whether it is the X Y problem.
somebody can help? thanks
i want create a bindingProxy template class which twoway bindable in qml
i think it should equivalence dynamicObject in wpf
Based on CloudMusicSongList I'm assuming the thing that you have is a list/array. There are quite a number of ways of exposing this to QML.
QQmlListProperty - https://doc.qt.io/qt-6/qqmllistproperty.html
QAbstractListModel - https://doc-snapshots.qt.io/qt6-dev/qabstractlistmodel.html
QVariant, QVariantList, and/or QVariantMap - https://doc-snapshots.qt.io/qt6-dev/qvariant.html
QObject / Q_OBJECT - create a new QML component and register it
Q_GADGET - register your C++ structure (good for access the class in a signal, but, QML/JS cannot copying it into a Javascript object, only good for the duration of the signal)
QQmlListProperty is a list of QObjects. It requires the underlying QObject be registered, but, allows you to create/manage and walk through a list of the results. The list is owned, usually by another QObject. e.g. we could have a QmlFile object, then implement a QmlFileSystem object that can return a list of QmlFiles.
QAbstactListModel can be used in places where a model is required, e.g. ListView.
QVariant, QVariantList and QVariantMap is the simplest way of creating a Javascript object in QML. The advantage is you do not have to register anything, but, the disadvantage is you do not get intellisense.
QVariant getBooks() {
QVariantList books;
QVariantMap book1;
book1["title"] = QString("Lord of the Rings");
QVariantMap book2;
book2["title"] = QString("The Hobbit");
books.append(book2);
return books;
// results in QML/JS:
// [ { "title": "Lord of the Rings" },
// { "title" : "The Hobbit" } ]
}
Related
here is my setup:
First is the model class, this stores a pointer to the data of type CompetitionsList. We can see that it implements the necessary basic functions when deriving from QAbstractListModel, and it uses the QML_ELEMENT macro to expose the model to the QML type system:
class CompetitionsListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(CompetitionsList* list READ list WRITE setList)
QML_ELEMENT
public:
explicit CompetitionsListModel(QObject *parent = nullptr);
enum {
NameRole = Qt::ItemDataRole(),
IdRole
};
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
CompetitionsList *list() const;
void setList(CompetitionsList *list);
virtual QHash<int, QByteArray> roleNames() const;
private:
CompetitionsList* m_list; \\ <--- ptr to data
};
Then we have the data class. This class is also a QML_ELEMENT, and it has a userid property. This is used to populate the QVector<listItem> by requesting data from a RESTful http server.
The two signals preItemAppended() and postItemAppended() are emitted when data is added to the QVector<listItem>. These signals are then connected to the Model as a way of notifying the model it must create a new row in the list. The important function here is populateCompetitions, which I explain below.
struct listItem {
QString competitionName;
QString competitionId;
};
class CompetitionsList : public QObject
{
Q_OBJECT
Q_PROPERTY(QString userId READ getUserId WRITE setUserId)
QML_ELEMENT
public:
explicit CompetitionsList(QObject *parent = nullptr);
void populateCompetitions(const QString& userId);
QVector<listItem> items();
QString getUserId() const;
void setUserId(const QString &value);
signals:
void preItemAppended();
void postItemAppended();
void errorPopulatingData();
private:
QVector<listItem> m_competitions;
QString userId;
};
The populateCompetitions function looks as so:
void CompetitionsList::populateCompetitions(const QString &userId)
{
qDebug() << "initialising data";
HttpClient* client = new HttpClient();
client->getUserCompetitions(userId);
connect(client, &HttpClient::getUserCompetitionsResult, [=](const QByteArray& reply){
QJsonDocument _reply = QJsonDocument::fromJson(reply);
if(_reply["data"].isNull()) {
emit errorPopulatingData();
}
else {
const QJsonArray competitions = _reply["data"]["competitions"].toArray();
for(const QJsonValue& competition : competitions) {
emit preItemAppended();
listItem item{competition["competition-name"].toString(), competition["competition-id"].toString()};
m_competitions.append(std::move(item));
emit postItemAppended();
}
}
});
}
It requests data from the database, and then stores it locally.
Then finally, the QML model which ties it all together:
ListView {
id: view
implicitHeight: 1920
implicitWidth: 1080
clip: true
model: CompetitionsListModel {
list: CompetitionsList {
id: compList
}
Component.onCompleted: { compList.userId = "6033f377257e8630ed13299e" } //<-- calls the populateCompetitions function
}
delegate: RowLayout {
Text {
text: qsTr(model.name + ":::" + model.id)
}
}
}
We can see that it has a ListView element, with a model of type CompetitionsListModel and a list of type CompetitionsList. Once the model component is created, we set the userId of the list, this in turn calls the populateCompetitions function which sets up the data for the model to use as seen above.
Unfortunately this doesnt anything when I run the code. Blank screen. Nada. I was wondering if anyone has an insight as to what might be causing this based on the code provided. Ive been at it for so long and it just inst being nice.
I think you need to call qmlRegisterType or UncreatableType on your CompetitionsListModel :
https://doc.qt.io/qt-5/qqmlengine.html#qmlRegisterType
Qt 5.8, Windows 10.
Quick Controls 2 application. In QML I have a ListView with a model derived from QAbstractListModel.
In the model I have the following code:
void MediaPlaylistModel::update()
{
beginResetModel();
{
std::unique_lock<std::mutex> lock(m_mutex);
m_ids = m_playlist->itemsIds();
}
endResetModel();
}
Nothing happens in QML view after calling this method: list is not updated.
If I go back and then forward (to the page with the ListView) - it'll contain updated data. Model object instance is the same always.
Am I doing something wrong?
Update #1:
The only methods I override are:
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
Update #2:
C++ model code:
MediaPlaylistModel::MediaPlaylistModel(
QSharedPointer<AbstractMediaPlaylist> playlist,
QObject *parent) :
base_t(parent),
m_playlist(playlist)
{
Q_ASSERT(m_playlist);
connect(playlist.data(), &AbstractMediaPlaylist::changed,
this, &MediaPlaylistModel::update);
update();
}
QHash<int, QByteArray> MediaPlaylistModel::roleNames() const
{
QHash<int, QByteArray> result;
result[IdRole] = "id";
result[TitleRole] = "title";
result[DurationRole] = "duration";
return result;
}
void MediaPlaylistModel::update()
{
Q_ASSERT_SAME_THREAD;
beginResetModel();
{
std::unique_lock<std::mutex> lock(m_mutex);
m_ids = m_playlist->itemsIds();
}
endResetModel();
}
int MediaPlaylistModel::rowCount(
const QModelIndex &parent) const
{
Q_UNUSED(parent);
std::unique_lock<std::mutex> lock(m_mutex);
return static_cast<int>(m_ids.size());
}
QVariant MediaPlaylistModel::data(
const QModelIndex &index,
int role) const
{
auto row = static_cast<size_t>(index.row());
int id = 0;
{
std::unique_lock<std::mutex> lock(m_mutex);
if (row >= m_ids.size())
return QVariant();
id = m_ids[row];
}
if (role == IdRole)
return id;
QVariant result;
auto item = m_playlist->item(id);
switch(role)
{
case Qt::DisplayRole:
case TitleRole:
result = item.title;
break;
case DurationRole:
result = item.duration;
break;
}
return result;
}
QML code:
import QtQuick 2.7
import QtQuick.Controls 2.0
import com.company.application 1.0
Page
{
id : root
property int playlistId
property var playlistApi: App.playlists.playlist(playlistId)
ListView
{
id : playlist
anchors.fill: parent
model: playlistApi.model
delegate: ItemDelegate
{
text: model.title
width: parent.width
onClicked: App.player.play(playlistId, model.id)
}
ScrollIndicator.vertical: ScrollIndicator {}
}
}
Update #3:
When the model is updated (one item added), something strange happens with QML ListView: in addition to fact that it's not updated (and it does not call
MediaPlaylistModel::data to retrieve new items), existing items got damaged. When I click on existed item, it's model.id property is always 0. E.g. at app start its model.id was 24, after one item added its model.id became 0.
Update #4:
App.playlists.playlist(playlistId) returns pointer to this class instance:
class CppQmlPlaylistApi :
public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* model READ model NOTIFY modelChanged)
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
public:
explicit CppQmlPlaylistApi(
int playlistId,
QWeakPointer<CorePlaylistsManager> playlistsMgr,
QObject *parent = 0);
QObject* model() const;
QString title() const;
void setTitle(const QString &title);
signals:
void modelChanged();
void titleChanged();
void loadPlaylistRequested(int id);
protected slots:
void onPlaylistLoaded(int id);
void onPlaylistRemoved(int id);
protected:
int m_playlistId = 0;
QWeakPointer<CorePlaylistsManager> m_playlistsMgr;
QSharedPointer<QAbstractItemModel> m_model;
};
The model was in non-GUI thread.
I was getting these debug messages (thanks to AlexanderVX for pointing me out):
QObject::connect: Cannot queue arguments of type 'QQmlChangeSet'
(Make sure 'QQmlChangeSet' is registered using qRegisterMetaType().)
Moving the model object to GUI thread fixed the problem.
Your code, as provided, is good. On the QML side, as long as your model is bound, and not dynamically re-created in JS, you should be good too.
ListView {
model: mediaPlaylistModel
}
Problems can arise if you overloaded beginResetModel or endResetModel by accident. For tests purposes, you can try to emit the QAbstractItemModel::modelReset() signal, and see if it changes anything.
It's quite easy to miss something with QAbstractItemModel, resulting in nothing working anymore !
I have to create an 2 custom events.
I followed this link & made my code :--
Is there a cleaner way to register Qt custom events?
Is it the right way to create & post & pass some data(Qstring) to the customized event ?
===========================================================
Edit code as per Kuba Ober sugession :---
Mainwindow.h :--
UpdateEvent *myUpdateEvent ;
ClearEvent *myClearEvent ;
Mainwindow.c :---
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
i =0;
myUpdateEvent = new UpdateEvent("hello");
myClearEvent = new ClearEvent("bye");
QCoreApplication::postEvent(this, myUpdateEvent);
QCoreApplication::postEvent(this, myClearEvent);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
qDebug() << "oo";
if (UpdateEvent::is(event)) {
UpdateEvent *tempUpdateEvent = static_cast<UpdateEvent *>(event);
qDebug() << tempUpdateEvent->value();
}
else if (ClearEvent::is(event)) {
ClearEvent *tempClearEvent = static_cast<ClearEvent *>(event);
qDebug() << tempClearEvent->value();
}
return true;
}
event.h file :--
template <typename T> class StringEvent : public QEvent
{
QString m_str;
public:
explicit StringEvent(const QString val) : QEvent(staticType()), m_str(val)
{
}
QString setvalue(QString val)
{
m_str = val;
}
QString value() const
{
return m_str;
}
static QEvent::Type staticType()
{
static int type = QEvent::registerEventType();
return static_cast<QEvent::Type>(type);
}
static bool is(const QEvent * ev)
{
return ev->type() == staticType();
}
};
class UpdateEvent : public StringEvent<UpdateEvent>
{
public:
explicit UpdateEvent(QString val): StringEvent(val)
{
}
};
class ClearEvent : public StringEvent<ClearEvent>
{
public:
explicit ClearEvent(QString val): StringEvent(val)
{
}
};
why eventFilter is not triggered ? And i am not able to see debug message on postevent ?
I can only comment on the code smell of your event implementation, since it is at this point unclear why would you need to send events to an edit control within a window. The latter is bad design.
Your Event class is needlessly complicated. You should be setting up all values inside the event during construction, and they should be accessible through read-only accessors afterwards. The extra event type seems to be an unnecessary gimmick as well.
Here's how I'd do it, using a metafactory pattern (a name I just coined, perhaps there's a better/existing name for it?). This solves the need for explicit derived class constructor injection that'd be otherwise needed.
I've split up the metafactory into small constituent classes for ease of understanding.
// A type-identifier-generating wrapper for events
template <typename D> class EventWrapper : public QEvent {
public:
EventWrapper() : QEvent(staticType()) {}
static QEvent::Type staticType() {
static QEvent::Type type = static_cast<QEvent::Type>(registerEventType());
return type;
}
static bool is(const QEvent * ev) { return ev->type() == staticType(); }
static D* cast(QEvent * ev) { return is(ev) ? static_cast<D*>(ev) : 0; }
};
// The generic event metafactory for C++98 (doesn't need C++11)
template <typename D, template <typename> class Carrier> class EventMF {
class EventFwd;
class Final;
class FinalWrapper : public EventWrapper<EventFwd>, public virtual Final {};
public:
// EventFwd is a class derived from Event. The EventWrapper's cast()
// will cast to a covariant return type - the derived class. That's OK.
typedef Carrier<FinalWrapper> Event;
private:
class EventFwd : public Event {};
class Final {
friend class FinalWrapper;
friend class Carrier<FinalWrapper>;
private:
Final() {}
Final(const Final &) {}
};
};
// A string carrier
template <typename B> class StringData : public B {
QString m_str;
public:
explicit StringData(const QString & str) : m_str(str) {}
QString value() const { return m_str; }
};
// A string event metafactory
template <typename D> class StringEventMF : public EventMF<D, StringData> {};
class Update : public EventMF<Update, StringData> {}; // using generic metafactory
class Clear : public StringEventMF<Clear> {}; // using specific metafactory
#if 0
// This should fail at compile time as such derivation would produce classes with
// duplicate event types. That's what the Final class was for in the matafactory.
class Error : public Update::Event { Error() : Update::Event("") {} };
#endif
int main(int, char**)
{
// Test that it works as expected.
Update::Event update("update");
Clear::Event clear("clear");
Q_ASSERT(Update::Event::staticType() != Clear::Event::staticType());
Q_ASSERT(Update::Event::staticType() == Update::Event::cast(&update)->staticType());
qDebug() << Update::Event::cast(&update)->value();
Q_ASSERT(Update::Event::cast(&clear) == 0);
qDebug() << Clear::Event::cast(&clear)->value();
Q_ASSERT(Clear::Event::cast(&update) == 0);
}
The Metafactory::Event classes are the custom event classes that derive from QEvent.
The class hierarchy for Update::Event looks as follows (going from the least derived to most derived class):
EventWrapper<EventMF<...>::EventFwd>, EventMF<...>::Final (multiple inheritance)
EventMF<Update, StringData<Update>>::FinalWrapper
StringData<Update> = EventMF<Update, StringData<Update>>::Event
with EventMF<...> being shorthand for EventMF<Update, StringData<Update>.
The line Update::Event update("update") constructs a custom string-carrying event instance, with the constructors called from the last to the first in the list above.
Since EventMF<...> is a metafactory that works at time of compilation only, there is absolutely no need for its instance to exist at runtime. Thus EventMF<...>::EventMF constructor is never called. You can enforce this invariant by deleting the constructor (declaring it private for C++98).
The use within an event handler would look like:
void MainWindow::customEvent(QEvent *event)
{
...
if (Update::Event::is(event)) {
qDebug() << Update::Event::cast(event)->value();
...
}
else if (Clear::Event::is(event)) {
...
}
...
}
I've created a QAbstractListModel derived model based on an underlying QHash. Since I need to use the model in QML, I cannot make use of the sorting functionality Qt widgets and views have integrated.
I tried using a QSortFilterProxyModel but it doesn't seem to work with my model. Getting the model to properly work in QML wasn't tedious enough, and now I am stuck on sorting.
Any suggestions are appreciated.
Here is the model source:
typedef QHash<QString, uint> Data;
class NewModel : public QAbstractListModel {
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
NewModel(QObject * parent = 0) : QAbstractListModel(parent) {}
enum Roles {WordRole = Qt::UserRole, CountRole};
QHash<int, QByteArray> roleNames() const {
QHash<int, QByteArray> roles;
roles[WordRole] = "word";
roles[CountRole] = "count";
return roles;
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
if (index.row() < 0 || index.row() >= m_data.size()) return QVariant();
Data::const_iterator iter = m_data.constBegin() + index.row();
switch (role) {
case WordRole:
return iter.key();
case CountRole:
return iter.value();
} return QVariant();
}
int rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent)
return m_data.size();
}
int count() const { return m_data.size(); }
public slots:
void append(const QString &word) {
bool alreadyThere = m_data.contains(word);
if (alreadyThere) m_data[word]++;
else m_data.insert(word, 1);
Data::const_iterator iter = m_data.find(word);
uint position = delta(iter);
if (alreadyThere) {
QModelIndex index = createIndex(position, 0);
emit dataChanged(index, index);
} else {
beginInsertRows(QModelIndex(), position, position);
endInsertRows();
emit countChanged();
}
}
void prepend(const QString &word) {
if (m_data.contains(word)) m_data[word]++;
else m_data.insert(word, 1);
}
signals:
void countChanged();
private:
uint delta(Data::const_iterator i) {
uint d = 0;
while (i != m_data.constBegin()) { ++d; --i; }
return d;
}
Data m_data;
};
Here is "trying" to sort it:
NewModel model;
QAbstractItemModel * pm = qobject_cast<QAbstractItemModel *>(&model);
QSortFilterProxyModel proxy;
proxy.setSourceModel(pm);
proxy.setSortRole(NewModel::WordRole);
proxy.setDynamicSortFilter(true);
Alas, the proxy works as a model, but it doesn't sort the entries.
If you enable QSortFilterProxyModel::setDynamicSortFilter(true), you need to call QSortFilterProxyModel::sort(...) function once to let the proxy know which way to sort.
With that, any time the model is updated the proxy will sort everything again just automatically.
proxy.setDynamicSortFilter(true);
proxy.sort(0);
First of all, There's no need for qobject_cast<QAbstractItemModel *> downcasting -- the NewModel is a derived class of the QAbstractItemModel and the polymorphism principle says that you can use a subclass everywhere where a parent class is applicable.
Second, your prepend method does not use beginInsertRows and endInsertRows. That's a violation of the MVC API. You'll get data corruption in the attached views and proxy models if you use it this way.
Third, you haven't mentioned whether you're actually using your proxy model as the model for the attached view :).
Finally, you are using QHash as a backing store of your data with QHash::iterator for insertion. That's an itneresting solution, but something which just cannot work -- an insertion or removal can cause the hash table to grow/shrink, which means changing all data you publish via your model indexes. This is just not going to work. Don't use QHash when you need a stable order. The O(n) complexity of your delta method should be interpreted as a warning; this is a wrong approach.
Have a Look at https://github.com/oKcerG/SortFilterProxyModel. This project exposes the functionality of QSortFilterProxyModel nicely to QML. I used it in different projects and it junst worked. However if you want to implement your own solution it's something to get your ideas.
I use QList<QObject*> as a model in my app. As there might be a lot of elements, I decided to use SectionScroller. When I try to scroll using the SectionScroller I'm getting a
Error: Unable to assign [undefined] to QString
What am I doing wrong?
My ListView is:
ListView
{
id: irrview
width: parent.width
model: irregulars.db // QList<QObject*>
anchors.top: caption.bottom
anchors.bottom: parent.bottom
clip: true
section.criteria: ViewSection.FirstCharacter
section.property: "form0"
section.delegate: Item {height: 10; width: parent.width; Text { text: section } } // for testing purposes
delegate: Rectangle
{
/**/
}
}
Thanks
EDIT: more code:
the irregulars header
class IrregularListWrapper : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<QObject*> db READ getdb NOTIFY langChanged)
Q_ENUMS(Language)
public:
enum Language
{
English = 0,
German = 1
};
IrregularListWrapper() : db(0) { setLang(German); }
~IrregularListWrapper() { delete db; }
QList<QObject*> getdb() const { return *db; }
Q_INVOKABLE void changeLang(Language l) { delete db; setLang(l); }
signals:
void langChanged();
protected:
void setLang(Language);
QList<QObject*> * db;
};
and the body of a function
void IrregularListWrapper::setLang(Language l)
{
switch (l)
{
case English:
db = new english;
langName = "English";
break;
case German:
db = new german;
langName = "German";
break;
}
emit langChanged();
}
the classes german, english are like that
class german : public QList<QObject*>
{
public:
german();
};
german::german()
{
append(new IrregularVerb("anfangen", "fing an", "angefangen"));
/*more like that*/
}
and IrregularVerb:
class IrregularVerb : public QObject
{
Q_OBJECT
Q_PROPERTY(QString form0 READ getForm0 NOTIFY formChanged)
Q_PROPERTY(QString form1 READ getForm1 NOTIFY formChanged)
Q_PROPERTY(QString form2 READ getForm2 NOTIFY formChanged)
public:
QString forms[3];
QString getForm0() const { return getForm(0); }
QString getForm1() const { return getForm(1); }
QString getForm2() const { return getForm(2); }
IrregularVerb(QString a, QString b, QString c) { forms[0] = a; forms[1] = b; forms[2] = c; }
protected:
const QString& getForm(const int& ind) const { return forms[ind]; }
signals:
void formChanged();
};
Edit 2: this doesn't work
If I do
QVariantList getdb() const { return QVariant::fromValue(*db); }
IrregularListWrapper.h:24: error: could not convert 'QVariant::fromValue(const T&) [with T = QList<QObject*>; QVariant = QVariant]()' from 'QVariant' to 'QVariantList {aka QList<QVariant>}'
If I remove the star, the error is similar.
EDIT3:
I found out this http://ruedigergad.com/2011/08/22/qml-sectionscroller-vs-qabstractlistmodel/
And found out that irregulars.db.get is undefined
And changed german and english to
class german : public AbstractIrregularList
and
class AbstractIrregularList : public QObject, public QList<QObject*>
{
Q_OBJECT
public:
Q_INVOKABLE QObject* get(int index) {return at(index);}
};
But even now, irregulars.db.get(0) gives error (Result of expression 'irregulars.db.get' [undefined] is not a function.)
Why is happening like that, that the Q_INVOKABLE is not detected? The Q_OBJECT macro is there
/edit5: Even when using QVariant the errors are still there. It can be either treated as QList or as QObject*.
If I am not wrong, you should use QVariantList instead QList<SomeClass> to expose list of elements from C++ to QML.
It should solve problem.
Supported types in QML
Try making code to look like this (in irregulars header):
Q_PROPERTY(QVariantList db READ getdb NOTIFY langChanged)
//...
QVariantList getdb() const {/*convert db to QVariantList*/ return converted_db;}
Or if you want to code look like from links you gave:
Q_PROPERTY(QVariantList db READ getdb NOTIFY langChanged)
//...
QVariant getdb() const {return QVariant::fromValue(db);}