Question

I have recently picked up Qt again, and started refreshing my memory. Creating a custom data model for a table was easy enough.

Now I am trying to retrieve the selected data. Take note that I use custom data objects.

Example of my custom model:

platform.h

class Platform
{
public:
    Platform();
    Platform(QString name);
    QString getName();
    void setName(QString name);
private:
    QString m_name;
};

Very simple data structure for testing purposes. I then implemented a QAbstractTableModel, the Data() method looks like this:

platformmodel.cpp

QVariant PlatformModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (index.row() >= m_platforms.size() || index.row() < 0)
        return QVariant();

    if (role == Qt::DisplayRole) {
        Platform platform = m_platforms.at(index.row());
        qDebug() << platform.getName();
        return platform.getName();
    }
    return QVariant();
}

What I understand from this code is, that for the selectable items, a String is always returned, instead of a platform object.

For displaying, this works fine, I see the actual objects in the view. Now I want to select the actual object from the model, and not just a QString.

So the method body would be something like:

void MainWindow::selectionChangedSlot(const QItemSelection &, const QItemSelection &)
{
    //get the text of the selected item
    const QModelIndex index = ui->lvPlatforms->selectionModel()->currentIndex();
    Platform selectedPlatform = index.data();//This returns a QVariant and will fail at compile time, but I want to achieve something along this line.
    setWindowTitle(selectedPlatform.getName());
}

P.s. Maybe I am trying to search on the wrong thing, I can find examples that use custom objects, but none talk about retrieving the selected item.

There has to be a better way then retreiving the string, then looping trough the list of platforms and comparing the name to the selected item.. If i have a big list, having to loop trough each item and do string comparison is not very efficient.

I hope my problem is clear enough. If something important lacks, let me know so I can edit my example.

EDIT

I tried Q_DECLARE_METATYPE(Platform);

And yes it works, it makes it possible to store it in a QVariant, the problem is, since for displaying, a String is always expected, or 9/10 times anyway. So far it seems impossible to have both text display AND get the full platform object from the selection model(i can do both individually.. pretty useless..)

Was it helpful?

Solution

You can create custom type compatible with QVariant using the macro Q_DECLARE_METATYPE. If you declare your class as a metatype, you can store it in a QVariant and extract it with a cast.

Here an example that show how to create a custom delegate which can display data from a custom class using QVariant :

class Data {
private:
    QString name;
    int value;
public:
    Data() : name(""), value(-1){}
    Data( QString n, int v ) : name(n), value(v){}
    QString text() {
        return QString( "Test %1 - %2" ).arg( name ).arg( value );
    }
};

Q_DECLARE_METATYPE( Data )

class Delegate : public QStyledItemDelegate {
protected:
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
        Data d = index.data().value<Data>();
        painter->drawText( option.rect, d.text() );
    }
};


int main( int argc, char **argv) {
    QApplication app(argc, argv, true);

    QVariant var0, var1, var2;
    var0.setValue(Data( "Item A", 0 ));
    var1.setValue(Data( "Item B", 1 ));
    var2.setValue(Data( "Item C", 2 ));

    QListView *view = new QListView();
    QStandardItemModel model(3, 1);

    model.setData( model.index( 0, 0 ), var0 );
    model.setData( model.index( 1, 0 ), var1 );
    model.setData( model.index( 2, 0 ), var2 );
    view->setModel( &model );
    view->show();
    view->setItemDelegate( new Delegate() );
    return app.exec();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top