[英]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 . 就是这样,您的列表视图包含两个项目: Kevin和Michael 。
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 &
传递,这就是我将其作为任务留给您的原因。
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. 在您已经介绍过的情况下,您实际上不需要创建自己的结构,即
BundleItem
和BundleItem
QStandardItem
子类。
QStandardItem
itself provides enough functionality to suit your needs. QStandardItem
本身提供了足够的功能来满足您的需求。 Just use QStandardItem::data and QStandardItem::setData . 只需使用QStandardItem :: data和QStandardItem :: 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
。
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.