Добавить класс к QStandardItemModel - PullRequest
0 голосов
/ 16 сентября 2018

Как я могу добавить свои элементы класса BundleItem в модель QStandardItem QListView? Когда они добавляются, я хочу использовать только свойство BundleItem Name, которое будет отображаться в виде списка. Мне бы хотелось, чтобы указатель на фактический элемент находился в UserRole модели, поэтому, когда пользователь дважды щелкает мышью и элемент в списке, сейчас он просто печатает на консоль отладчика или что-то подобное.

#include "mainwindow.h"
#include <QVBoxLayout>
#include <QListView>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QAbstractItemModel>

struct BundleItem {
  QString name;
  QString nickname;
  QString team;

  // Constructor
  BundleItem(QString name,
             QString nickname,
             QString team):
      name(name), nickname(nickname), team(team)
  {}
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    auto *proxyModel = new QSortFilterProxyModel;
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);

    auto *widget = new QWidget(this);
    auto *lay = new QVBoxLayout(widget);
    auto *listview = new QListView();

    auto *model = new QStandardItemModel();
    proxyModel->setSourceModel(model);
    listview->setModel(proxyModel);

    // add Item to list
    BundleItem("Kevin", "Kev", "Coyotes");
    BundleItem("Michael", "Mike", "Walkers");

    lay->addWidget(listview);
    setCentralWidget(widget);
}

MainWindow::~MainWindow()
{

}

Ответы [ 3 ]

0 голосов
/ 16 сентября 2018

Нет необходимости использовать указатель, вы можете сохранить только одну копию, но должна быть возможность конвертировать ее в QVariant. Чтобы ваша структура могла быть преобразована в QVariant, вы должны использовать макрос Q_DECLARE_METATYPE и иметь конструктор по умолчанию. Я также добавил возможность использования QDebug напрямую со своей структурой.

*. Ч

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
class QListView;
class QStandardItemModel;
class QSortFilterProxyModel;

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void onDoubleClicked(const QModelIndex & index);
private:
    QListView *listview;
    QStandardItemModel *model;
    QSortFilterProxyModel *proxyModel;
    QWidget *widget;
};

#endif // MAINWINDOW_H

*. Каст

#include "mainwindow.h"

#include <QListView>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QVBoxLayout>

#include <QDebug>

struct BundleItem {
    QString name;
    QString nickname;
    QString team;

    // Constructor
    BundleItem() = default;
    BundleItem(const QString & name,
               const QString & nickname,
               const QString & team):
        name(name), nickname(nickname), team(team)
    {}
};
Q_DECLARE_METATYPE(BundleItem)

QDebug operator<<(QDebug debug, const BundleItem &b)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << '(' << b.name << ", " << b.nickname << ", "<< b.team <<')';
    return debug;
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    proxyModel = new QSortFilterProxyModel(this);
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);

    widget = new QWidget(this);
    auto lay = new QVBoxLayout(widget);
    listview = new QListView();

    model = new QStandardItemModel();
    proxyModel->setSourceModel(model);
    listview->setModel(proxyModel);

    // add Item to list
    BundleItem item1("Kevin", "Kev", "Coyotes");
    BundleItem item2("Michael", "Mike", "Walkers");

    for(const BundleItem & e : {item1, item2}){
        QStandardItem *it = new QStandardItem(e.name);
        it->setData(QVariant::fromValue(e));
        model->appendRow(it);
    }
    connect(listview, &QListView::doubleClicked, this, &MainWindow::onDoubleClicked);
    lay->addWidget(listview);
    setCentralWidget(widget);
}

MainWindow::~MainWindow()
{

}

void MainWindow::onDoubleClicked(const QModelIndex &index)
{
    QVariant v = proxyModel->data(index, Qt::UserRole+1);
    BundleItem b = v.value<BundleItem>();
    qDebug()<< b;
}

Преимущество использования копии заключается в том, что вам не придется обращаться с памятью и, следовательно, меньше проблем. При использовании прокси не требуется доступ к исходной модели, поэтому для доступа к этим данным вы можете сделать это из модели прокси. С другой стороны, если вы собираетесь передать QString в качестве аргумента функции или метода, и он не изменит его лучше, передайте его как const QString &, по этой причине я оставляю это вам как задачу.

0 голосов
/ 16 сентября 2018

Решение

Ответы @ rafix07 и @eyllanesc являются на 100% правильными и решают проблему, о которой вы спрашивали.

Однако я позволю себе предложить другое направление в вашем дизайне, потому что:

В случае, если вы представили, вам на самом деле не нужно создавать свою собственную структуру, т.е. BundleItem и подкласс QStandardItem в этом отношении.

QStandardItem сам по себе обеспечивает достаточную функциональность для удовлетворения ваших потребностей. Просто используйте QStandardItem :: data и QStandardItem :: setData .

Примечание: Для вашего удобства вы можете создать enum со значением каждой информации, например, использовать что-то вроде ItemTeam вместо Qt::UserRole + 1.

Пример

Вот пример, который я подготовил для вас, чтобы продемонстрировать предложенный мной подход:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class QStandardItem;

class MainWindow : public QMainWindow
{
    enum DataType : int {
        ItemName = Qt::DisplayRole,
        ItemNickName = Qt::UserRole,
        ItemTeam
    };

    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = nullptr);

    QStandardItem *createItem(QString name, QString nickname, QString team);

private slots:
    void onDoubleCLicked(const QModelIndex &index);
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "MainWindow.h"
#include <QStandardItem>
#include <QSortFilterProxyModel>
#include <QBoxLayout>
#include <QListView>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    auto *proxyModel = new QSortFilterProxyModel;
    proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);

    auto *widget = new QWidget(this);
    auto *lay = new QVBoxLayout(widget);
    auto *listview = new QListView();

    auto *model = new QStandardItemModel();
    proxyModel->setSourceModel(model);
    listview->setModel(proxyModel);

    // add Item to list
    model->appendRow(createItem("Kevin", "Kev", "Coyotes"));
    model->appendRow(createItem("Michael", "Mike", "Walkers"));

    lay->addWidget(listview);
    setCentralWidget(widget);

    connect(listview, &QListView::doubleClicked, this, &MainWindow::onDoubleCLicked);
}

QStandardItem *MainWindow::createItem(QString name, QString nickname, QString team)
{
    auto *item = new QStandardItem(name);

    item->setData(nickname, ItemNickName);
    item->setData(team, ItemTeam);

    return item;
}

void MainWindow::onDoubleCLicked(const QModelIndex &index)
{
    if (index.isValid())
        qDebug() << index.data(ItemName).toString() << index.data(ItemNickName).toString() << index.data(ItemTeam).toString();
}
0 голосов
/ 16 сентября 2018

Легкая версия для этого - наследование от QStandardItem класса.

struct BundleItem : public QStandardItem {
  QString name;
  QString nickname;
  QString team;

  BundleItem(QString name,
             QString nickname,
             QString team):
      QStandardItem(name), // call constructor of base class - name will be displayed in listview
      name(name), nickname(nickname), team(team)
  {}
};

Не забудьте вызвать конструктор QStandardItem в ctor BundleItem и передать name в качестве егопараметр.

Строки для добавления ваших элементов в ListView:

model->appendRow (new BundleItem("Kevin", "Kev", "Coyotes"));
model->appendRow (new BundleItem("Michael", "Mike", "Walkers"));

и все, у вас есть список, заполненный двумя элементами: Кевин и Майкл .

Если вы хотите обработать действие двойного щелчка, вы можете использовать в своем слоте

handleDoubleClick (const QModelIndex&); // declaration of your slot

метод QStandardItemModel::indexFromItem(const QModelIndex&), который принимает QModelIndex (индекс передачи из слота) какпараметр и возвращает указатель на QStandardItem.Вам нужно только привести этот указатель к BundleItem, тогда у вас есть доступ к другим членам вашего класса.

...