BlinCTOct. 24, 2019, 12:42 p.m.

Заполнение tableModel из структуры

Всем привет.
Пытаюсь заполнить таблицу из структуры которую передаю обьекту вектором.
Может я где то ошибаюсь, undefind reference получаю. Но почему непонятно.
Ниже кидаю код класса.

#pragma once

#include <QtCore/QAbstractTableModel>
#include <sources/structs/wrappers/nvme/Tables.hpp>

template <typename T>
class TableModel : public QAbstractTableModel
{
public:
    explicit TableModel(QVector<T > vec);

    [[nodiscard]] int rowCount(const QModelIndex &parent) const override;

    [[nodiscard]] int columnCount(const QModelIndex &parent) const override;

    [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;

    [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override;

private:
    int m_rowCount;
    int m_columnCount;

    QVector<T* > m_vec;

    QVector<QString> m_vecSupPowerState;
};
#include <QDebug>

#include "TableModel.hpp"

template <typename T>
TableModel<T>::TableModel(QVector<T > vec)
    : m_vec(vec)
    , m_rowCount(vec.size())
    , m_columnCount(0)
{
    m_vecSupPowerState.push_back("St");
    m_vecSupPowerState.push_back("Op");
    m_vecSupPowerState.push_back("Max");
    m_vecSupPowerState.push_back("Active");
    m_vecSupPowerState.push_back("Idle");
    m_vecSupPowerState.push_back("RL");
    m_vecSupPowerState.push_back("RT");
    m_vecSupPowerState.push_back("WL");
    m_vecSupPowerState.push_back("WT");
    m_vecSupPowerState.push_back("Ent_Lat");
    m_vecSupPowerState.push_back("Ex_lat");

    if (m_vec == QVector<SupportedPowerStates>())
    {
        qDebug() << "SupportedPowerStates";
    }
}

template <typename T>
int TableModel<T>::rowCount(const QModelIndex &parent) const
{
    return m_vec.size();
}

template <typename T>
int TableModel<T>::columnCount(const QModelIndex &parent) const
{
    return 0;
}

template <typename T>
QVariant TableModel<T>::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
    {
        return QVariant();
    }

    int row = index.row();
    int col = index.column();

    switch (role)
    {
        case Qt::DisplayRole:
            return QString("%1, %2").arg(index.column()).arg(index.row());
        default:
            break;
    }

    return QVariant();
}

template <typename T>
QVariant TableModel<T>::headerData(int section, Qt::Orientation orientation, int role) const
{
    if( role != Qt::DisplayRole )
    {
        return QVariant();
    }

    if( orientation == Qt::Vertical )
    {
        return section;
    }

    switch( section )
    {
        case 0:
            return tr( "St" );
        case 1:
            return tr( "Op" );
        case 2:
            return tr( "Max" );
        case 3:
            return tr( "Active" );
        case 4:
            return tr( "Idle" );
        case 5:
            return tr( "RL" );
        case 6:
            return tr( "RT" );
        case 7:
            return tr( "WL" );
        case 8:
            return tr( "WT" );
        case 9:
            return tr( "Ent_Lat" );
        case 10:
            return tr( "Ex_lat" );

    }

}

Если видите в конструкторе я просто воткнул проверку, только для теста, то есть обьекту могут прилететь разыне структуры, у них разное колличество строк и столбцов.
Так же в конструкторе заполняется вектор который будет использоватся если прилетит SupportedPowerStates которая как раз в конструкторе и проверяется.
Вопрос такой, не знаю как проверять в случаи если данная структура прилетела и дял нее использовать данные поля.
И приму любые советы если есть какие то ошибки в реализации.

В main.cpp я создаю обьект таким способом

auto tableModel = new TableModel<QVector<SupportedPowerStates> >(nvmeIdCtrl->getSupportedPowerStates());
engine.rootContext()->setContextProperty("tableModel", tableModel);

Как раз данный метод и возвращает вектор такой структуры.

Спасибо.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
13

Привет.
Зачем использовать таблицу, когда по факту здесь обрабатывается одна строка? Несмотря на то, что по задумке видимо каждый объект должен прдставлять собой именно строку.
При этом в headerData возвращаешь заголовки для горизонтальной ориентации. section в том случае - это номер колонки.
Почему coulmnCount возвращает 0? в данном случае он возвращать должен как минимум 1, если следовать задумке.

Вообще, вместо того, чтобы шаманить шаблоны. Лучше передавать в таблицу указатель на интерфейсный класс, а передаваемые в вектор объекты должны будут реализовывать этот интерфейс.

По поводу передачи одной строки это пока просто был тест, туда будет именно таблица лететь, ну то есть вектор векторов.
В headerData там был просто начальный набросок, и как я написал там будет в зависимости какая структура такая структура с заголовками и будет.
Там я заготовил одну из них. В coulmnCount возвращение 0 это пока дефолтно.

Вместо вектора векторов лучше использовать класс или структуру. Или лучше я говорил интерфейсный класс или базовый абстрактный класс. В большинстве случае можно и без шаблона обойтись.

Полагаю, что undefined reference относится скорее к проблеме внутри main функции, полный текст кода хотелось бы видеть.

Либо проблема может быть в том, что шаблоны и Q_OBJECT не совместимы. То есть либо пишется шаблонная модель, либо модель с макросом Q_OBJECT.
Либо можно написать шаблонную модель, от которой наследуется конкретная реализация с Q_OBJECT. Такое тоже работает. Но одновременно в одном классе нет. Тоже самое и где-то в документации написано.

А конкретно для QML отсутствие макроса Q_OBJECT может быть критично, поскольку не создаётся правильная метаинформация.

Это лишь мысли, проверять нужно. Но скорее всего так. Лучше уже полиморфизм, чем шаблоны в данном случае.

Ты бы мог простой набросок скинуть как бы выглядела реализация с таким интерфейсом для разного рода контейнеров со структурами и как бы они определялись в модели для заполнения таблицы?

Вот пример класса интерфейса и класса потомка

#ifndef MODELOBJECT_H
#define MODELOBJECT_H

#include <QVariant>

class IModelObject
{
public:
    virtual ~IModelObject() {};
    virtual QVariant getMainInfo() const = 0;
    virtual QString getName() const = 0;
    virtual QVariant getValue() const = 0;
};

class IntModelObject : public IModelObject
{
public:
    IntModelObject() : IModelObject() {}
    virtual ~IntModelObject() {}

    virtual QVariant getMainInfo() const override { return QString("IntModelObject %1 %2").arg(m_name).arg(m_value); }
    virtual QString getName() const override { return QString("IntModelObject %1").arg(m_name); }
    virtual QVariant getValue() const override { return m_value; }

private:
    int m_value;
    QString m_name;
};

#endif // MODELOBJECT_H

Можешь наследоваться от интефейса и определять стандартизированное поведение, например у тебя есть методы:

  • получения основной информации
  • получения имени
  • получения значения в виде QVariant

А дальше внутри модели хранишь только вектор указатель на интерфейс

QVector<IModelObject*> m_objects;

Дальше в модель загружаешь через какой-нибудь метод указатели на любые объекты, классы которых наследованы от интерфейса.

А внутри модели уже крутишь всё как хочешь. Смысл тот же, что у тебя и есть.

Если же тебе нужно совсем различное поведение в разных таблицах, то имеешь одну базовую таблицу, наследуешься от неё, и переопределяешь только то, что тебе нужно.

Так, тут в принципе немного ясно становится. Но наследование от QAbstractTableModel идет также на IntModelObject и других потомкой что будут работать со своим типом структур?

Все, по поводу модели понял.

Хотел уточнить с тем что я написал и правильно ли понял:

#pragma once

#include <QVariant>

class IModelObject
{
public:
    virtual ~IModelObject() = default;
    virtual QVariant getMainInfo() const = 0;
    virtual QVariant getName() const = 0;
    virtual QVariant getValue() const = 0;
};

/////////////////////////////

#pragma once

#include "IModelObject.hpp"

class SupPowerStatesModelObject : public IModelObject
{
public:
    explicit SupPowerStatesModelObject();   // как понимаю туда в конструктор должна прилетать уже готовая структура которая потом станет таблицей
    ~SupPowerStatesModelObject() override = default;

    QVariant getMainInfo() const override;

    QVariant getName() const override;

    QVariant getValue() const override;
};

///////////////////////////////////

#pragma once

#include <QtCore/QAbstractTableModel>
#include <sources/structs/wrappers/nvme/Tables.hpp>
#include "IModelObject.hpp"

class TableModel : public QAbstractTableModel
{
public:
    explicit TableModel();

    [[nodiscard]] int rowCount(const QModelIndex &parent) const override;

    [[nodiscard]] int columnCount(const QModelIndex &parent) const override;

    [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;

    [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override;

    void setObject(IModelObject* object) const; // метод через который сюда передаются обьекты со структурами

private:
    int m_rowCount;
    int m_columnCount;

    QVector<IModelObject* > m_object;
};

Правильно ли все в этой реализации и коменты что я подписал?

И вот так уже я в main.cpp передаю один из обьектов с данными

    SupPowerStatesModelObject sub;
    auto tableModel = new TableModel();
    tableModel->setObject(sub);

Если в конструктор передавать какую-то структуру, которую должен поддерживать тот класс, то в принципе да. в общем-то правильно будет. Конкретная реализация уже покажет ошибки в процессе.

Что касается метода setObject, то здесь его лучше переименовать в addObject. Поскольку перевоначальное наименование не отражает сути метода. Ты добавляешь объекты, и их может быть много в этой модели. Тогда как setObject априори подразумевает только один объект, который будет находится в классе, в который добавляется данный объект. Ну и совсем явная ошибка, это наличие модификатора const у метода setObject. Данный метод модифицирует состояние модели данных, а значит никак не может быть константным.

Спасибо, вроде немного стало более ясно. С ошибкой тоже.
Получается что

void setObject(IModelObject* object);

получая обьект уже определяет что это за обьект из наследников и уже у модели внутри что то с каждым делает?

Внутри он просто закидывает в вектор этот объект, и всё

void aadObject(IModelObject* object)
{
    m_objects.push_back(object);
}

Дальше в методах модели просто вызываешь методы, которые созданы в абстрактном классе IModelObject.
Твоя задача определить рееализацию в классах, которые наследованы от IModelObject. Это класс является интерфейсом.
Он формирует унифицированный интерфейс, а задача остальных классов наследников реализовать эти интерфейсы.
Если сможешь унифицировать поведение тех различных структур, то сможешь обобщить большую часть и использовать меньшее число моделей, чем по модели на каждый вид структуры

Хорошо, понял.
Вообще разница тех контейнеров что несут в себе структуры только в том что разное колличество столбцов, строк, названий столбцой. Ну и данные само собою.

Количество строк роли не играет, поскольку это всего лишь размер контейнера.
А вот количество столбцов - это более сложный вопрос.
Из-за разного количества столбцов скорее всего придётся делать наследованные модели и расширять поведение. Одним унифицированным интерфейсом не обойтись.

Comments

Only authorized users can post comments.
Please, Log in or Sign up
How to become an author?

Contribute to the evolution of the EVILEG community.

Learn how to become a site author.

Learn it
Donate

Good day, Dear Users!!!

I am Evgenii Legotckoi, developer of EVILEG. And it is my hobby project, which helps to learn programming another programmers and developers

If the site helped you, and you want also support the development of the site, than you can donate by following ways

PayPalYandex.Money
Timeweb

Let me recommend you the excellent hosting on which EVILEG is located.

For many years, Timeweb has been proving his stability.

For projects on Django I recommend VDS hosting

View Hosting
KA

C++ - Тест 003. Условия и циклы

  • Result:78points,
  • Rating points2
R

C++ - Test 002. Constants

  • Result:75points,
  • Rating points2
R

C++ - Test 001. The first program and data types

  • Result:73points,
  • Rating points1
Last comments
V

Django - Tutorial 027. Implementation Google reCAPTCHA

Спасибо. Только использую декоратор не в urls.py а перед views
R

Qt WinAPI - Lesson 001. How to collect all DLL, which used in Qt project?

Вы меня не совсем правильно поняли, но все равно спасибо, принял все к сведению. Все сделал как вы сказали, все отлично работает, еще раз огромнейшее спасибо) Разве что только что были опять про…

Qt WinAPI - Lesson 001. How to collect all DLL, which used in Qt project?

Стоило перед использованием что ли инструкцию прочитать https://www.cyberforum.ru/blogs/131347/blog2457.html "После сборки при запуске требовались dll," Ясное дело стоило задепло…
R
R

Qt WinAPI - Lesson 001. How to collect all DLL, which used in Qt project?

Да, собралось. После сборки при запуске требовались dll, перекинул всю папки bin, plugins(не знаю как можно было сделать более умно). Как я понял в первой строке путь к екзешнику вставляю, втор…
Now discuss on the forum

QML+QtGraphicalEffects

Вот здесь пишут, что решение поиска библиотеки был в добавлении QML_IMPORT_PATH -> StackOverflow QML_IMPORT_PATH += /opt/Qt5.8.0/5.8/gcc_64/qml/QtGraphicalEffect…

Не работают слоты/сигналы

и посмотрите работу с потоками в Qt, там подробно описано как передавать данные с одного в потока в другой при помощи сигналов и слотов

Как в Qt в qmenu добавить scrollarea

Вот это наследованный класс меню. Но посути это обычное меню. #pragma once#include <QtWidgets>class TransMenu : public QMenu { Q_OBJECTpublic: TransMenu(QWidget* parent = …

Qt C++ и Python

Красиво/некрасиво - это скорее моё личное отношение. Если есть возможность ограничить количество интсрументов, то лучше ограничить. Но не зацикливайтесь на этом. Если у вас есть скрипты Py…

Qt + OpenGL glDeleteVertexArrays

Я не уверен, поскольку с OpenGL очень мало работал. Но может быть OpenGL контекст виджета нужно переинициализовывать. И ещё виджет стоит удалять через метод deleteLater() а не п…
About
Services
© EVILEG 2015-2020
Recommend hosting TIMEWEB