如何将我的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()
{
}
答案 0 :(得分:2)
最简单的方法是继承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"));
仅此而已,列表视图由两个项目填充: Kevin 和 Michael 。
如果要处理双击操作,可以在广告位中使用
handleDoubleClick (const QModelIndex&); // declaration of your slot
方法QStandardItemModel::indexFromItem(const QModelIndex&)
,它以QModelIndex
(来自插槽的索引)作为参数,并返回指向QStandardItem
的指针。您只需要将此指针转换为BundleItem
,就可以访问该类的其他成员。
答案 1 :(得分:2)
没有必要使用指针,您只能保存一个副本,但必须可以将其转换为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 &
传递,这就是我将其作为任务留给您的原因
答案 2 :(得分:2)
@ 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();
}