简体   繁体   English

将类追加到QStandardItemModel

[英]Append Class to QStandardItemModel

How can I append my items of class BundleItem to the QListView's QStandardItem model? 如何将我的BundleItem类的项追加到QListView的QStandardItem模型中? When they are appended, I only want to use the BundleItem's Name property to be displayed in the listview. 附加它们后,我只想使用BundleItem的Name属性在列表视图中显示。 I would like a pointer to the actual item to live in the UserRole of the model so when a user double clicks and item in the list, for now it would just print to the debugger console or something similar. 我希望有一个指向实际项目的指针存在于模型的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()
{

}

The easy version to do it is inheritance from QStandardItem class. 做到这一点的简单版本是从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)
  {}
};

Remember to call QStandardItem constructor in ctor of BundleItem and passing name as its parameter. 请记住在BundleItem ctor中调用QStandardItem构造BundleItem ,并将名称作为其参数传递。

Lines to add your items to ListView are: 将项目添加到ListView的行是:

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

and it is all, you have listview filled by two items : Kevin and Michael . 就是这样,您的列表视图包含两个项目: KevinMichael

If you want to handle double-click action, you can use in your slot 如果要处理双击动作,可以在广告位中使用

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

method QStandardItemModel::indexFromItem(const QModelIndex&) which takes QModelIndex (pass index from slot) as parameter and returns pointer to QStandardItem . 方法QStandardItemModel::indexFromItem(const QModelIndex&)QModelIndex (从插槽传递索引)为参数,并返回指向QStandardItem指针。 You need only to cast this pointer to BundleItem then you have access to other members of your class. 您只需要将此指针转换为BundleItem访问类的其他成员。

It is not necessary to use a pointer, you can save only one copy but it must be possible to convert it to QVariant . 不必使用指针,您只能保存一个副本,但是必须可以将其转换为QVariant So that your structure can be converted to QVariant you must use the Q_DECLARE_METATYPE macro and have a default constructor. 为了将您的结构转换为QVariant ,必须使用Q_DECLARE_METATYPE宏并具有默认构造函数。 I have also added the possibility of using QDebug directly with its structure. 我还添加了直接使用QDebug及其结构的可能性。

*.h *。H

#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

*.cpp *的.cpp

#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;
}

The advantage of using a copy is that you will not have to handle memory and therefore fewer problems. 使用副本的优点是您不必处理内存,因此问题更少。 When using a proxy it is not necessary to access the source model, so to access that data you can do it from the proxy model. 使用代理时,无需访问源模型,因此可以从代理模型中访问数据。 On the other hand if you are going to pass QString as an argument of a function or method and it will not modify it better, pass it as const QString & , the reason I leave it as a task for you. 另一方面,如果要将QString作为函数或方法的参数传递,并且不会更好地对其进行修改,请将其作为const QString &传递,这就是我将其作为任务留给您的原因。

Solution

The answers from @rafix07 and @eyllanesc are both 100% correct and solve the problem you have asked about. @ rafix07和@eyllanesc的答案都是100%正确,可以解决您所询问的问题。

However, I will allow myself the liberty to suggest a different direction in your design, because: 但是,我将允许我自由提出设计的另一个方向,因为:

In the case you have presented, you do not actually need to create your own structure, ie BundleItem , and subclass QStandardItem for that matter. 在您已经介绍过的情况下,您实际上不需要创建自己的结构,即BundleItemBundleItem QStandardItem子类。

QStandardItem itself provides enough functionality to suit your needs. QStandardItem本身提供了足够的功能来满足您的需求。 Just use QStandardItem::data and QStandardItem::setData . 只需使用QStandardItem :: dataQStandardItem :: setData即可

Note: For your convenience you could create an enum with the meaning of each data, eg to use something like ItemTeam instead of Qt::UserRole + 1 . 注意:为方便起见,您可以创建一个包含每个数据含义的enum ,例如使用ItemTeam之类的ItemTeam代替Qt::UserRole + 1

Example

Here is an example I have prepared for you to demonstrate the approach I have suggested: 这是我为您准备的一个示例,以演示我建议的方法:

MainWindow.h 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 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM