@Neyury

Как правильно выводить информацию из QVector?

Требуется реализовать простой каталог. Создал класс описывающий объект каталога. Добавил несколько экземпляров класса в QVector и попытался вывести это в таблицу, создавая для каждого поля QTableWidgetItem, но в итоге при непустом векторе у меня крушится программа с кодом 3. Так что видимо я делаю что то не так, и возникают следующие вопросы:

Как очистить виджет(или Layout) от всех дочерних виджетов? (При каждом изменении каталога, я планировал пересоздавать новую таблицу)

Как бы вы реализовали вывод изменяющийся информации? (Может быть я мыслю не в том направлении)
  • Вопрос задан
  • 970 просмотров
Решения вопроса 1
@Free_ze
Пишу комментарии в комментарии, а не в ответы
Откройте для себя Model/View в Qt. В частности, ваша задачка с каталогами описана здесь.

Вкратце: у вас есть модель, в котором вы связываете ваш способ хранения (QVector в вашем случае) со стандарным интерфейсомQAbstractItemModel (или его потомки QAbstractListModel, QAbstractTableModel или QAbstractTreeModel), который можно передать в один из стандартных вью-виджетов (QListView, QTableView, QTreeView). Реализовав интерфейс (переопределив виртуальные методы data и setData для role==Qt::DisplayRole и Qt::EditRole), вы можете просто изменять состояние модели, а вью-виджеты подхватят изменения автоматически.

Кроме того, есть еще такая штука - QDataWidgetMapper. Он умеет привязывать виджеты (даже обычные, не View) к определенным полям в модели.
Пример

Пример объемный, но минимально полный, содержащий всю необходимую инфраструктуру. Допустим, мы хотим создать редактор для некоторых статей (блога?). Нам нужен простой класс Article, чтобы собрать в кучу данные о каждой отдельной статье:

class Article
{
public:
    Article(int id, const QString& title, const QString& content) 
        : _id(id), _title(title), _content(content) {}

    int id() const { return _id; } 
    void setId(int id) { _id = id; }

    QString title() const { return _title; } 
    void setTitle(const QString& title) { _title = title; }

    QString content() const { return _content; }
    void setContent(const QString& content) { _content = content; }

private:
    int     _id;
    QString _title;
    QString _content;
};

Для него напишем модель хранения этих статей - ArticlesModel, содержащей массив статей и методы для их добавления/удаления. Кроме того, для нее мы реализуем стандартный интерфейс QAbstractTableModel (методы rowCount, columnCount, data и setData), чтобы виджеты знали, как оттуда брать и как обновлять данные.

class ArticlesModel :
        public QAbstractTableModel
{
public:
    ArticlesModel(QObject *parent=nullptr);

    void addArticle(const Article& art);
    void removeArticle(int id);

    //QAbstractTableModel interface implamentation
    int rowCount(const QModelIndex &/*parent*/) const override;
    int columnCount(const QModelIndex &/*parent*/) const override;

    bool data(QModelIndex& index, const QVariant &value, int role) const override;
    QVariant setData(QModelIndex& index, int role) override;
    
private:
    std::vector<Article> _articles;
};

// =================================================================

ArticlesModel(QObject *parent/*=nullptr*/) 
    : QAbstractTableModel(parent)
{
}

void ArticlesModel::addArticle(const Article& art) {
    _articles.push_back(art);
}
void ArticlesModel::removeArticle(int id) {
    auto found = std::find_if(begin(_articles), end(_articles), 
                            [id](const Article& art) {
                                art.id() == id;
                            });
    if (found != std::end(_articles)) {
        _articles.erase(artIt);
    }
}


int ArticlesModel::rowCount(const QModelIndex &/*parent*/) const override {
    return _articles.size();
}
int ArticlesModel::columnCount(const QModelIndex &/*parent*/) const override {
    return 2;
}

bool ArticlesModel::data(QModelIndex& index, const QVariant &value, int role) const override {
    if (!index.isValid) return QVariant();

    if (role == Qt::EditRole) {
        switch (column) {
            case 0: 
                QVariant(_articles[index.row()].setTitle(value.toString()));
                return true; 
            case 1:
                QVariant(_articles[index.row()].setContent(value.toString()));
                return true; 
        }
    }
    return false;
}

QVariant ArticlesModel::setData(QModelIndex& index, int role) override {
    if (!index.isValid) return QVariant();

    if (role == Qt::DisplayRole || role == Qt::EditRole) {
        switch (column) {
            case 0: return QVariant(_articles[index.row()].title()); 
            case 1: return QVariant(_articles[index.row()].content());
        }
    }
    return QVariant();
}


Тогда можно сделать так:

// this - это какой-то родительский виджет

auto titleEditor = new QLineEdit(this);
auto contentEditor = new QTextEdit(this);

QAbstractTableModel *model = new ArticlesModel(this);
model->addArticle(Article(1, "Hello title", "Hello content"));
model->addArticle(Article(2, "Another title", "Another content"));

auto mapper = new QDataWidgetMapper(this);
mapper->setModel(model);
mapper->addMapping(titleEditor, 0);
mapper->addMapping(contentEditor, 1);
mapper->toFirst(); // Переключаемся на первый элемент модели


Теперь мы можем добавлять/удалять статьи в model->add/removeArticle(const Article&), переходить с заметки на заметку с помощью mapper->setCurrentIndex(int index), менять содержимое заметок в редакторе.

Можно добавить QListView, так же передать туда модель через setModel() и связать сигнал изменения текущего элемента списка с тем же действием mapper, добавить пару кнопок для добавления/удаления заметок и мы получим полноценный редактор.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы