I'm coming from c++ and I'm having difficulties making my classes work the way I want them to. The program I am building is rather simple. The user creates an album or two and can fill that album with cards. Those albums are created dynamically on run time.
Here is my initial class diagram for the back-end c++ stuff: class diagram
And here is how the UI looks like: QML UI
The crux of the problem: A set of changes to the classes are necessary to make them available to QML.
- Inheritance: Classes need to inherit from QObject or QAbstractListModel depending on their role.
- Containers: Dynamically instantiated objects within an object, through pointers or not, need to be placed in a QList or something similar.
- Root context property: The model needs to be registered so that it can be made available in a Listview for example.
I have had some success setting an instance of an Album class, with some changes made to it, as a root context property. The model worked correctly and the cards in the album displayed correctly in a ListView.
The problem here is that I need to step out of the picture another level, I should set a class that contains the Albums as the root context property and let the user create, and add, Albums to it during run time. I will also need to also display the albums and the cards inside them through different views.
I am wondering if I should implement a table/tree data structure for the albums and the cards and somehow pass the columns and rows to the models or If there is a tidier approach that I am not aware of.
Here are my classes so far:
album.h
#ifndef ALBUM_H
#define ALBUM_H
#include <QObject>
#include <QString>
#include <QAbstractListModel>
#include <QQmlListProperty>
#include "card.h"
class Album : public QAbstractListModel
{
Q_OBJECT
public:
enum AlbumRoles {
CardIDRole = Qt::UserRole + 1,
NameRole,
ImageURLRole,
SubtypeRole,
SupertypeRole,
NumberRole,
ArtistRole,
RarityRole,
SeriesRole,
SetRole,
SetCodeRole,
ConditionRole,
StatusRole
};
Album(QObject *parent = 0);
QString name() const;
void addCard(const Card &card);
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
protected:
QHash<int, QByteArray> roleNames() const;
private:
QList<Card> m_cards;
QString m_name;
};
album.cpp
#include "album.h"
Album::Album(QObject *parent)
: QAbstractListModel(parent)
{
}
QString Album::name() const
{
return m_name;
}
void Album::addCard(const Card &card)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_cards << card;
endInsertRows();
}
int Album::rowCount(const QModelIndex & parent) const {
Q_UNUSED(parent);
return m_cards.count();
}
QVariant Album::data(const QModelIndex & index, int role) const {
if (index.row() < 0 || index.row() >= m_cards.count())
return QVariant();
const Card &card = m_cards[index.row()];
if (role == CardIDRole)
return card.cardID();
else if (role == NameRole)
return card.name();
else if (role == ImageURLRole)
return card.imageURL();
else if (role == SubtypeRole)
return card.subtype();
else if (role == SupertypeRole)
return card.supertype();
else if (role == NumberRole)
return card.number();
else if (role == ArtistRole)
return card.artist();
else if (role == RarityRole)
return card.rarity();
else if (role == SeriesRole)
return card.series();
else if (role == SetRole)
return card.set();
else if (role == SetCodeRole)
return card.setCode();
else if (role == ConditionRole)
return card.condition();
else if (role == StatusRole)
return card.status();
return QVariant();
}
QHash<int, QByteArray> Album::roleNames() const {
QHash<int, QByteArray> roles;
roles[CardIDRole] = "cardID";
roles[NameRole] = "name";
roles[ImageURLRole] = "imageURL";
roles[SubtypeRole] = "subtype";
roles[SupertypeRole] = "supertype";
roles[NumberRole] = "number";
roles[ArtistRole] = "artist";
roles[RarityRole] = "rarity";
roles[SeriesRole] = "series";
roles[SetRole] = "set";
roles[SetCodeRole] = "setCode";
roles[ConditionRole] = "condition";
roles[StatusRole] = "status";
return roles;
}
card.h
#ifndef CARD_H
#define CARD_H
#include <QString>
class Card
{
public:
// Standard Qt constructor with parent for memory management
Card(const QString &cardID, const QString &name, const QString &imageURL, const QString &subtype, const QString &supertype, const int &number, const QString &artist, const QString &rarity, const QString &series, const QString &set, const QString &setCode, const QString &condition, const QString &status);
QString cardID() const;
QString name() const;
QString imageURL() const;
QString subtype() const;
QString supertype() const;
int number() const;
QString artist() const;
QString rarity() const;
QString series() const;
QString set() const;
QString setCode() const;
QString condition() const;
QString status() const;
private:
// private members
QString m_cardID;
QString m_name;
QString m_imageURL;
QString m_subtype;
QString m_supertype;
int m_number;
QString m_artist;
QString m_rarity;
QString m_series;
QString m_set;
QString m_setCode;
QString m_condition;
QString m_status;
};
#endif //CARD_H
card.cpp
#include "card.h"
// Standard Qt constructor with parent for memory management
Card::Card(const QString &cardID, const QString &name, const QString &imageURL, const QString &subtype, const QString &supertype, const int &number, const QString &artist, const QString &rarity, const QString &series, const QString &set, const QString &setCode, const QString &condition, const QString &status): m_cardID(cardID), m_name(name), m_imageURL(imageURL), m_subtype(subtype), m_supertype(supertype), m_number(number), m_artist(artist), m_rarity(rarity), m_series(series), m_set(set), m_setCode(setCode), m_condition(condition), m_status(status)
{
}
QString Card::cardID() const
{
return m_cardID;
}
QString Card::name() const
{
return m_name;
}
QString Card::imageURL() const
{
return m_imageURL;
}
QString Card::subtype() const
{
return m_subtype;
}
QString Card::supertype() const
{
return m_supertype;
}
int Card::number() const
{
return m_number;
}
QString Card::artist() const
{
return m_artist;
}
QString Card::rarity() const
{
return m_rarity;
}
QString Card::series() const
{
return m_series;
}
QString Card::set() const
{
return m_set;
}
QString Card::setCode() const
{
return m_setCode;
}
QString Card::condition() const
{
return m_condition;
}
QString Card::status() const
{
return m_status;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include "app.h"
#include "album.h"
#include "card.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<Album>("Classes.PokemonApp", 1, 0, "Album");
qmlRegisterType<Card>("Classes.PokemonApp", 1, 0, "Card");
App pokeApp;
Album myAlbumModel;
Card cardOne("xy7-2","Gloom","http://s3.amazonaws.com/pokemontcg/xy7/2.png","Stage 1","Pokémon",2,"Masakazu Fukuda","Uncommon","XY","Ancient Origins","xy7","Mint","In my collection");
Card cardTwo("xy7-7","Sceptile-EX","https://s3.amazonaws.com/pokemontcg/xy7/7.png","EX","Pokémon",7,"Eske Yoshinob","Rare Holo EX","XY","Ancient Origins","xy7","Used","Duplicate");
myAlbumModel.addCard(cardOne);
myAlbumModel.addCard(cardTwo);
pokeApp.addAlbum(myAlbumModel);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("pokeApp", &pokeApp);
return app.exec();
}
CardsView.qml
import QtQuick 2.0
import Classes.PokemonApp 1.0
// Cards Deligate
ListView {
width: 200; height: 250
model: myAlbumModel
delegate: Text { text: "Card:"
+ "\n" + "ID: " + cardID
+ "\n" + "Name: " + name
+ "\n" + "Image URL: " + imageURL
+ "\n" + "Subtype: " + subtype
+ "\n" + "Supertype: " + supertype
+ "\n" + "Number: " + number
+ "\n" + "Artist: " + artist
+ "\n" + "Rarity: " + rarity
+ "\n" + "Series: " + series
+ "\n" + "Set: " + set
+ "\n" + "Set code: " + setCode
+ "\n" + "Condition: " + condition
+ "\n" + "Status: " + status }
}
So to be clear, this is what I need help with: Give the user the ability to create albums during run time, let the user add cards to albums and have models display the albums and the cards in them in different views.