代码之家  ›  专栏  ›  技术社区  ›  JokerMartini

将类附加到QStandardItemModel

  •  1
  • JokerMartini  · 技术社区  · 7 年前

    Name 要在listview中显示的属性。我想要一个指向模型的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 回复  |  直到 6 年前
        1
  •  2
  •   rafix07    7 年前

    最简单的方法是继承 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)
      {}
    };
    

    记得打电话 的构造函数 BundleItem 名称 作为其参数。

    将项目添加到ListView的行包括:

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

    总之,listview中有两项内容: 迈克尔 .

    如果要处理双击操作,可以在插槽中使用

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

    QStandardItemModel::indexFromItem(const QModelIndex&) 这需要 QModelIndex (从插槽传递索引)作为参数并返回指向 Q标准项目 . 您只需将此指针投射到 然后你就可以接触你班上的其他同学了。

        2
  •  2
  •   eyllanesc Yonghwan Shin    7 年前

    QVariant . 这样你的结构就可以转换成 Q变量 Q_DECLARE_METATYPE 宏和具有默认构造函数。我还添加了使用 QDebug 与它的结构直接相关。

    *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
    

    #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 & ,所以我把它作为一项任务留给你。

        3
  •  2
  •   Community CDub    5 年前

    @rafix07和@eyllanesc的答案都是100%正确的,并且解决了您所问的问题。

    然而,我将允许我自己的自由,建议在您的设计不同的方向,因为:

    在您已经介绍的情况下,您实际上不需要创建自己的结构,即。 BundleItem QStandardItem 关于那件事。

    它本身提供了足够的功能来满足您的需要。只是使用 QStandardItem::data QStandardItem::setData .

    为了您的方便,您可以创建一个 enum 每个数据的含义,例如使用 ItemTeam 而不是 Qt::UserRole + 1 .

    主窗口.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
    

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