将 Class 附加到 QStandardItemModel
Append Class to QStandardItemModel
如何将 class BundleItem 的项附加到 QListView 的 QStandardItem 模型?附加它们时,我只想使用 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()
{
}
最简单的版本是从 QStandardItem
class.
继承
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
的构造函数中调用 QStandardItem
构造函数并将 name 作为参数传递。
将项目添加到 ListView 的行是:
model->appendRow (new BundleItem("Kevin", "Kev", "Coyotes"));
model->appendRow (new BundleItem("Michael", "Mike", "Walkers"));
就是这样,您有两个项目填充的列表视图:Kevin 和 Michael.
如果你想处理双击动作,你可以在你的插槽中使用
handleDoubleClick (const QModelIndex&); // declaration of your slot
方法 QStandardItemModel::indexFromItem(const QModelIndex&)
以 QModelIndex
(从插槽传递索引)作为参数和 returns 指向 QStandardItem
的指针。您只需将此指针转换为 BundleItem
然后您就可以访问 class.
的其他成员
不一定要用指针,可以只保存一份,但必须可以转换成QVariant
。为了使您的结构可以转换为 QVariant
,您必须使用 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
*.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;
}
使用副本的好处是您不必处理内存,因此问题更少。使用代理时,无需访问源模型,因此要访问该数据,您可以从代理模型中进行。另一方面,如果您要将 QString
作为函数或方法的参数传递并且它不会更好地修改它,请将其作为 const QString &
传递,这是我将其作为任务留给您的原因.
解决方案
The answers from @rafix07 and @eyllanesc are both 100% correct and solve the problem you have asked about.
但是,我可以自由地为您的设计建议不同的方向,因为:
在您介绍的情况下,您实际上不需要创建自己的结构,即 BundleItem
和子类 QStandardItem
。
QStandardItem
本身提供了足够的功能来满足您的需要。只需使用 QStandardItem::data and 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();
}
如何将 class BundleItem 的项附加到 QListView 的 QStandardItem 模型?附加它们时,我只想使用 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()
{
}
最简单的版本是从 QStandardItem
class.
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
的构造函数中调用 QStandardItem
构造函数并将 name 作为参数传递。
将项目添加到 ListView 的行是:
model->appendRow (new BundleItem("Kevin", "Kev", "Coyotes"));
model->appendRow (new BundleItem("Michael", "Mike", "Walkers"));
就是这样,您有两个项目填充的列表视图:Kevin 和 Michael.
如果你想处理双击动作,你可以在你的插槽中使用
handleDoubleClick (const QModelIndex&); // declaration of your slot
方法 QStandardItemModel::indexFromItem(const QModelIndex&)
以 QModelIndex
(从插槽传递索引)作为参数和 returns 指向 QStandardItem
的指针。您只需将此指针转换为 BundleItem
然后您就可以访问 class.
不一定要用指针,可以只保存一份,但必须可以转换成QVariant
。为了使您的结构可以转换为 QVariant
,您必须使用 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
*.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;
}
使用副本的好处是您不必处理内存,因此问题更少。使用代理时,无需访问源模型,因此要访问该数据,您可以从代理模型中进行。另一方面,如果您要将 QString
作为函数或方法的参数传递并且它不会更好地修改它,请将其作为 const QString &
传递,这是我将其作为任务留给您的原因.
解决方案
The answers from @rafix07 and @eyllanesc are both 100% correct and solve the problem you have asked about.
但是,我可以自由地为您的设计建议不同的方向,因为:
在您介绍的情况下,您实际上不需要创建自己的结构,即 BundleItem
和子类 QStandardItem
。
QStandardItem
本身提供了足够的功能来满足您的需要。只需使用 QStandardItem::data and 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();
}