Russian Qt Forum

Qt => Model-View (MV) => Тема начата: UVV от Март 27, 2009, 10:29



Название: vector of structs and QAbstractTableModel
Отправлено: UVV от Март 27, 2009, 10:29
Воспользовавшись поиском, обнаружил, что на эту тему люди задают вопросы в этот раздел, хотя я и не понимаю почему =)

Вопрос в следующем. Допустим есть vector addrSeq структур:
Код:
struct myStruct
{
    int a;
    string b;
    stricg c;
}
Есть офигительное желание натянуть поверх неё QAbstractTableModel =)
Пока не придумал ничего интереснее чем:
Код:
int myModel::columnCount(const QModelIndex &parent) const
{
    return 3;
}

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

    if (index.row() >= addrSeq.size())
        return QVariant();

    if (role == Qt::DisplayRole)
    {
        struct myStruct desc = addrSeq[index.row()];
        switch (index.column())
        {
            case 0:
                return QString("%1").arg(desc.a);
            case 1:
                return QString::fromUtf8(desc.b.c_str());
            case 2:
                return QString::fromUtf8(desc.c.c_str());
        }
    }
    else
        return QVariant();
}

QVariant myTableModel::headerData(int section,
                    Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();

    if (orientation == Qt::Horizontal)
        return QString("Column %1").arg(section);
    else
        return QString("Row %1").arg(section);
}


Как бы вы посоветовали реализовать такое более грамотно?


Название: Re: vector of structs and QAbstractTableModel
Отправлено: Barmaglodd от Март 27, 2009, 11:23
Я также делаю.


Название: Re: vector of structs and QAbstractTableModel
Отправлено: UVV от Март 27, 2009, 12:58
Я также делаю.
Т.е. получается под каждую структуру свою модель? =)


Название: Re: vector of structs and QAbstractTableModel
Отправлено: Racheengel от Март 27, 2009, 13:00
разве что
Код:
struct myStruct desc = addrSeq[index.row()];
заменить на
Код:
const struct myStruct& desc = addrSeq[index.row()];

чтобы лишний раз не делать копирование структур (будет пошустрее)


Название: Re: vector of structs and QAbstractTableModel
Отправлено: Racheengel от Март 27, 2009, 13:01
Я также делаю.
Т.е. получается под каждую структуру свою модель? =)

Что значит "под каждую структуру свою модель" ?


Название: Re: vector of structs and QAbstractTableModel
Отправлено: UVV от Март 27, 2009, 13:13
Что значит "под каждую структуру свою модель" ?
Это значит, что вектор не один, а их много и они все с разными структурами))


Название: Re: vector of structs and QAbstractTableModel
Отправлено: Racheengel от Март 27, 2009, 13:16
Тогда передавай его в конструктор модели по поинтеру.
А в модели используй поинтер.


Название: Re: vector of structs and QAbstractTableModel
Отправлено: UVV от Март 27, 2009, 13:20
Тогда передавай его в конструктор модели по поинтеру.
А в модели используй поинтер.

Я говорю вот об этом:
Код:
        switch (index.column())
        {
            case 0:
                return QString("%1").arg(desc.a);
            case 1:
                return QString::fromUtf8(desc.b.c_str());
            case 2:
                return QString::fromUtf8(desc.c.c_str());
        }

Для каждой структуры придётся делать свою модель, где вот этот фрагмент будет отличаться.
Т.е. для структуры myStruct2 модель должна быть уже другой.
Код:
struct myStruct1
{
    int a;
    string b;
    stricg c;
}

struct myStruct2
{
    int d;
    int e;
    stricg f;
}


Название: Re: vector of structs and QAbstractTableModel
Отправлено: Racheengel от Март 27, 2009, 13:55
можно конечно и свою модель, а можно делегаты разные сделать в зависимости от типа структур.


Название: Re: vector of structs and QAbstractTableModel
Отправлено: Barmaglodd от Март 27, 2009, 13:56
Да, для каждой структуры своя модель. Если поля интегральных типов и строки, можно сделать функцию, которая конвертирует структуру в массив QVariant'ов, и передавать их в модель, тогда класс модели будет один. Либо сделать интерфейс, который позволяет получить по индексу QVariant c представлением данного поля, и наследников от него - конкретные реализации для каждого класса структур. Либо сделай для каждого класса структур что-то типа type_traits с информацией о полях и их типе, и используй шаблонного наследника от QAbstractItemModel. Наверно можно ещё кучу вариантов придумать.


Название: Re: vector of structs and QAbstractTableModel
Отправлено: Sergeich от Март 30, 2009, 02:38
Либо сделай для каждого класса структур что-то типа type_traits с информацией о полях и их типе, и используй шаблонного наследника от QAbstractItemModel.
При использовании шаблонного наследника от QAbstractItemModel могут возникнуть проблемы, т.к. moc не поддерживает шаблоны в наследниках QObject, лучше использовать абстрактный интерфейс для получения данных из вектора, а в его реализации использовать шаблоны.
 Например, надо построить модель для вектора из трехмерных точек QVector<Point3D>:
В структуру Point3D добавляем метод для получения координаты по индексу и два статических метода для получения числа элементов структуры и названий элементов
Код:
struct Point3D
{
Point3D( float _x = 0, float _y = 0, float _z = 0 ) : x(_x), y(_y), z(_z) {}

float x;
float y;
float z;

QVariant data(int i) const { return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : QVariant(); }
static int count() { return 3; }
static QStringList names() { return QStringList() << "X" << "Y" << "Z"; }
};
Объявляем интерфейс для получения данных:
Код:
class AbstractTableData 
{
public:
virtual QVariant data( int row, int col ) const = 0;
virtual int rowCount() const = 0;
virtual int columnCount() const = 0;
virtual QVariant headerData(int) const { return QVariant(); }
};
Делаем шаблонную реализацию этого интерфейса:
Код:
template <class T>
class TableData : public AbstractTableData, public QVector<T>
{
public:
QVariant data( int row, int col ) const { return value(row).data(col); }
int rowCount() const { return size(); }
int columnCount() const { return T::count(); }
QVariant headerData(int i) const { return T::names().value(i); }
};
Реализуем модель:
Код:
class TableModel : public QAbstractTableModel
{
Q_OBJECT
public:
TableModel( AbstractTableData* data, QObject* parent ) : QAbstractTableModel(parent), m_data(data) {}
int rowCount ( const QModelIndex& ) const { return m_data->rowCount(); }
int columnCount ( const QModelIndex& ) const { return m_data->columnCount(); }
QVariant data ( const QModelIndex& index, int role ) const {
return role ==  Qt::DisplayRole ? m_data->data( index.row(), index.column() ) : QVariant();
  }
QVariant headerData ( int section, Qt::Orientation orientation, int role ) const {
if (role ==  Qt::DisplayRole)
return (orientation == Qt::Horizontal) ? m_data->headerData( section ) : section + 1;
return QVariant();
}
private:
AbstractTableData* m_data;
};
Юзаем:
Код:
int main( int argc, char** argv )
{
QApplication app( argc, argv );

TableData<Point3D> data;
for ( int i = 0; i < 100; i++ )
data << Point3D( i % 10, i / 10, (i % 10) * (i / 10) );

TableModel model( &data, 0 );

QTableView view;
view.setModel( &model );
view.resize( 400, 600 );
view.show();

return app.exec();
}


Название: Re: vector of structs and QAbstractTableModel
Отправлено: Barmaglodd от Март 30, 2009, 08:23
При использовании шаблонного наследника от QAbstractItemModel могут возникнуть проблемы, т.к. moc не поддерживает шаблоны в наследниках QObject, лучше использовать абстрактный интерфейс для получения данных из вектора, а в его реализации использовать шаблоны.
Всё зависит от того, как вы этого наследника будете использовать ;)
http://doc.trolltech.com/qq/qq15-academic.html (http://doc.trolltech.com/qq/qq15-academic.html)