C++ 如何使QAbstractTableModel与数据存储保持同步?
在我的应用程序中,我有一个用于保存项目列表的类:C++ 如何使QAbstractTableModel与数据存储保持同步?,c++,qt,qtableview,qabstractitemmodel,C++,Qt,Qtableview,Qabstractitemmodel,在我的应用程序中,我有一个用于保存项目列表的类: class Database : public QObject { Q_OBJECT public: Database(QObject *parent, const QString &name); const Entry& item(int idx) const { Q_ASSERT(idx < itemCount()); return _items.at(idx); } const QS
class Database : public QObject
{
Q_OBJECT
public:
Database(QObject *parent, const QString &name);
const Entry& item(int idx) const { Q_ASSERT(idx < itemCount()); return _items.at(idx); }
const QString& name() const { return _name; }
int itemCount() const { return _items.size(); }
bool addItem(const Entry &item);
bool addItems(const Database *source, const QList<int> &idxs);
bool updateItem(int idx, const Entry &updated);
void removeItem(int idx);
void removeItems(const QList<int> &idxs);
private:
QList<Entry> _items;
signals:
void itemsRemoved(int start, int count);
void itemsAdded(int count);
void itemChanged(int index);
void countUpdate();
};
我在使模型反映对其当前数据库的更改方面遇到问题。以前,每当数据库中发生变化时(由数据库发送到数据库模型的信号触发),我都会发出一个模型重置来让它工作,但我认为这太过分了。现在我不知道如何正确连接数据库和模型
将数据库信号连接到模型并使模型发出dataChanged()不起作用,因为数据库中的项数(以及模型的行数)正在更改。QAbstractTableModel中有名为rowsInserted()和rowsRemoved()的信号,但文档称它们不能用于自定义类。要重新实现的虚拟函数有removeRows()和insertRows(),但文档中说我必须在它们内部调用begin(Remove | Insert)Rows()和end(Remove | Insert)Rows(),这导致了两个问题:
编辑:实际上这并不重要,现在我将通过QModelIndex()来实现这一点。QAbstractTreeModel使用它来标识树中的父节点,表模型显然不需要它
如何使模型与数据库保持同步?谢谢 我想我明白你的问题了。 一方面,你做了正确的事情,试图将数据与模型分开,另一方面,你的数据并不知道模型本身 在更改数据之前调用begin…Rows(),然后调用end…Rows()是有原因的。即
QPersistentModelIndex
。通常情况下,您不应该hortQModelIndex
对象,但持久索引需要保存和保留。模型必须保证其有效性。看看那些begin…Rows()方法的代码,主要是关于持久索引的
您有多种选择。a) 如果您肯定不会使用持久性索引,那么您可以在模型中实现一个私有插槽,用于侦听来自数据源的某种更新信号。这个插槽只需调用begin…Rows()和end…Rows(),中间没有任何内容。它不是“干净的”,但它会工作的 b) 您可以在数据源中实现更多信号,一个信号表示数据更改的开始(例如删除或添加行),另一个信号表示所述操作的结束。当然,这将大大增加代码的大小 c) 你可以让你的
数据库成为模型中的类朋友,并调用begin。。。结束。。。来自数据源中的方法,但是数据库
必须知道该模型
d) 你可以重新思考这个概念。据我所知,您正在使用数据库
类作为模型的数据存储和代码其他部分的接口,对吗?
使用自定义项和对模型本身进行操作的方法,从而避免麻烦,不是更容易吗?我已经做了我应该做的,所以如果需要的话我可以给你代码
希望这能有所帮助。
致以最诚挚的问候感谢您不辞劳苦,把它说得那么清楚。我尝试了a)并且成功了,但我不喜欢“不干净”。)最后我做了一些类似c)的事情。现在,数据存储保留了一个指向模型的指针,并调用了它的两个公共函数,这两个函数在对数据进行适当操作之前开始…Rows(),之后结束…Rows()。最后,我想我会做d),也许在下一个版本中进行其他重构无论哪种方式,我都对模型如何知道数据存储中发生了更改以及视图如何更新(只是没有行添加/删除)感到困惑。没有信号从数据存储连接到任何东西。我甚至让它成为非Q_对象,但不知怎么的,它仍然有效。也许你知道幕后发生了什么?谢谢实际上是的。视图不断轮询模型,但这主要适用于可访问角色、装饰角色和工具提示角色等角色。当您从数据中删除一行时,视图将轮询该数据(查找某些内容),并注意到数据已移动。因此,一行消失了,但在底部有一个额外的空行。我很确定,如果在此之后调整视图大小,多余的行将消失,因为这将调用模型的rowCount()
方法。您可以从接口派生模型并向该接口传递指针,而不是向数据源传递模型指针。。这样,数据源只能通过接口访问有限数量的模型类功能。
class DatabaseModel : public QAbstractTableModel
{
Q_OBJECT
public:
DatabaseModel(QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const { return _data->itemCount(); }
int columnCount(const QModelIndex &parent = QModelIndex()) const { return 5; };
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0;
void setDatabase(const Database *data);
{
beginResetModel();
_data = data;
endResetModel();
}
protected:
const Database *_data;
};