Completely stuck on something that should be fairly trivial.(QAbstractTableModel with custom objects)



  • Greetings,

    I'm fairly new here(been stalking around, but never made an account) but i'm so stuck right now that I seem to have no choice.

    The problem:
    I am writing a simple application for teaching myself Qt, I try to use the docs and examples as much as possible.

    For convinience, I will post my question asked on Stackoverflow here aswell: "StackOverflow question":http://stackoverflow.com/questions/15128956/qabstracttablemodel-retrieve-custom-object-on-data-changed/15130836#comment21305558_15130836

    The application I am writing uses a Platform class, that has just a few properties.
    I want to be able to display a List<Platform> in a tableView/listview. For this I made a custom platformmodel, to act as a layer
    between the tableView and the Platforms, platformmodel extends QAbstractTableModel. Editting is not an issue right now. It should be read only.

    @#include <QString>
    #include <QMetaType>

    class Platform
    {
    public:
    Platform();
    Platform(const QString name, const int year);
    ~Platform();

    QString getName();
    void setName(QString name);
    int getYear() { return m_year; }
    void setYear(int year) { m_year = year; }
    
    QString toString() const {
        return m_name;
    }
    

    private:
    QString m_name;
    int m_year;
    };

    Q_DECLARE_METATYPE(Platform);@

    @#include <QAbstractTableModel>
    #include <QList>
    #include "platform.h"

    class PlatformModel : public QAbstractTableModel
    {
    Q_OBJECT
    public:
    PlatformModel(QObject *parent = 0);
    PlatformModel(QList<Platform> listOfPlatforms, QObject *parent = 0);

    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    QList<Platform> getPlatforms();
    

    private:
    QList<Platform> m_platforms;
    };

    #endif // PLATFORMMODEL_H@

    The headache starts at the implementation of data()
    @ if (role == Qt::DisplayRole) {
    Platform platform = m_platforms.at(index.row());
    //QVariant platformQVar;
    //platformQVar.setValue(platform);
    return platform.getName();
    }@

    Note the commented parts. Here is my greatest confusion:
    The current code returns a QVariant that wraps a QString, because getName returns a QString.
    Should I uncomment the code and return platformQVar, I get a wrapped platform, but nothign to display in the view itself.

    So at this point I have to choose, wether I want to be able to retrieve a QString or a Platform in SelectionChangedSlot

    @void MainWindow::selectionChangedSlot(const QItemSelection &, const QItemSelection &)
    {
    //get the text of the selected item
    const QModelIndex index = ui->lvPlatforms->selectionModel()->currentIndex();
    Platform selectedPlatform = qvariant_cast<Platform>(index.data());
    qDebug() << selectedPlatform.getName();
    qDebug() << selectedPlatform.getYear();
    setWindowTitle(selectedPlatform.getName());
    }@

    with the comments UNCOMMENTED the qDebug lines display exactly what I want. But the VIEW is empty, there is no "display" data
    with the comments commented, returning a QString, the code above just returns a string and the qDebug respectively ALWAYS displays: "", 0

    While it should display:

    @ QList<Platform> platforms;
    Platform ps3("Playstation 3", 1990);
    Platform xbox360("XBox 360", 1990);
    Platform wii("Wii", 1990);@

    "Playstation 3", 1990. This does not work when I return a QString wrapped QVariant in data(), because it only returns the display data from the view.

    I am completely clueless about how to get BOTH results. Maybe I am naive, but this should be trivial, or I just don't understand Qt(im quite new in actually using it)

    Sorry for the long post, Just want to make sure my problem is understood, and hopefully it will help others in the process, as using a custom viewmodel with custom data object tutorials and examples seem non existant.


  • Lifetime Qt Champion

    Hi,

    If you simply want to show that string, then you're doing it right. The alternative you have is to create a delegate that knows how to use your Platform class to paint something (I would recommend that for later but it's interesting to have a look at it).

    Since you have a custom type, one good way is to add a getter to your model
    @Platform platformForIndex(const QModelIndex &index) const @

    that retrieves a Platform for a given index so you can easily get the data you need.

    You can also add a custom role for data() that would return a QVariant containing a Platform object.

    @if (role == PlatformModel::PlatformRole) {
    return QVariant::fromValue(m_platforms.at(index.row());
    }
    @

    Hope it helps



  • Thanks alot SGaist, this works flawlessly.
    I implemented the getter for the model, and I now have the desired result.

    I am however also interested in the alternate answers.
    How does a QVariant know its role?

    And I implemented a delegate, it works for showing what I want and retrieving the data objects.
    The implementation is as followed

    (taken from answer in my SO thread)

    @ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
    Platform platform = index.data().value<Platform>();
    painter->drawText(option.rect, platform.toString());
    }@

    With this code, the view pretty much loses on how to show a selection.. It can do the actual selection, just not repesent it visually.

    Also, what if I want a custom row in a listview that will display these platforms, so that I have for example a title, with a date of release as sub title(a label right underneath)

    So again, the initial question is answered. Thanks alot for that!.


  • Lifetime Qt Champion

    You're welcome !

    As for the selection problem, you have to do some more painting (the option parameters, gives you the needed information to know i.e the selection state and other details).

    Have a look at the examples in the MVC chapter of the docs, i.e. the star delegate. That should give you a base to start.



  • A few hours have since passed, I have gotten quite far now actually. I got the selection working. Delegates work great! just needs getting used to, don't have the luxury that JavaFX provides on automatic sizing(for this particular usecase)

    Started out with your suggestion of using a simple getter, as that worked, I moved on to delegates, because I had to go there anyway at some point.
    Even understand how to make custom rows now, for example with 2 pieces of text in it.

    Actually, im recreating a Java app to Qt, it is kind of funny(and pathethic) to see the memory usage difference between the two, mostly because of JVM overhead. Trying to suggest Qt at work.

    Have to make a demo.

    Thanks again. I'm a big step ahead. I should be able to implement the majority of the sample project without too much problems.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.