在我的应用程序中,我有一个类来保存项目列表:
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();
};
项操作函数(add、update、remove)在完成操作(添加、更改、删除项)时发出相应的信号。我有这样的数据库的列表和一个QTableView显示他们的内容。我还有一个定制的对象,qabstracttablemodel派生的模型类,它可以在需要时指向(并显示)不同的数据库:
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;
};
我有一个问题,使模型反映其当前数据库的变化。在此之前,我通过每次数据库中的某些更改(由从数据库到DatabaseModel的信号触发)发出模型重置来实现它的工作,但我认为这有点过头了。现在我不知道如何正确连接数据库和模型。
将Database信号连接到模型并使模型发出datachchanged()不起作用,因为Database中的项数(因此模型的行数)正在变化。在QAbstractTableModel中有称为rowsInserted()和rowsRemoved()的信号,但是文档说它们不能在自定义类中使用。有一些虚函数要重新实现,叫做removeRows()和insertRows(),但是文档说我必须在它们里面调用begin(Remove|Insert)Rows()和end(Remove|Insert)Rows(),这会导致两个问题:
- Rows()需要一个QModelIndex '父'参数,我不知道该使用什么
- 文档说这些函数需要在更改底层数据存储 之前调用
EDIT:实际上这并不重要,现在我正在传递QModelIndex()。QAbstractTreeModel使用它来标识树中的父节点,对于表模型显然不是必需的。
如何使模型与数据库保持同步?谢谢!
我想我明白你的问题了。一方面,你正在做正确的事情,并试图保持数据与模型分离,另一方面,你的数据不知道模型本身。
在更改数据之前调用begin…Rows(),然后调用end…Rows()是有原因的。即QPersistentModelIndex
。通常情况下,您不应该对QModelIndex
对象进行保存,但是持久化索引应该被保存和保留。模型必须保证其有效性。看看begin…Rows()方法的代码,它主要是关于那些持久索引的。
你有几个选择。
a)如果你确信你不会使用持久索引,你可以在你的模型中实现一个私有槽,它可以从你的数据源中侦听一种更新信号。这个槽只调用begin…Rows()和end…Rows(),中间没有任何内容。它不"干净",但它会工作。
b)您可以在数据源中实现更多信号,一个信号表示数据更改的开始(例如删除或添加一行),另一个信号表示所述操作的结束。当然,这会大大增加代码的大小。
c)你可以把你的DataBase
类在模型中作为朋友,并调用begin…结束……方法,但是DataBase
必须知道模型。
DataBase
类作为模型的数据存储和代码其他部分的接口,对吗?使用自定义项和操作模型本身的方法不是更容易吗,从而避免了麻烦?我已经做了我的公平分享,所以我可以给你的代码,如果需要的话。
希望这对你有帮助。
最好的祝福