[Qt-interest] Item moves in tree models
Pavel Lebedev
cygnus at michiru.ru
Sat Oct 9 04:23:38 CEST 2010
Hi, I've been trying to implement item moving in a tree item model with
QAbstractItemModel::beginMoveRows()/endMoveRows(), but haven't been able to
figure out why a rather simple case is failing. Here's a minimal example:
//-------------------------------------------------------------------------
#include <QtCore/QAbstractItemModel>
#include <QtGui/QApplication>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <QtGui/QTreeView>
class Model : public QAbstractItemModel
{
Q_OBJECT
private:
struct Node
{
QString name;
Node* parent;
QList<Node*> children;
};
Node* root;
Node* nodeFromIndex(const QModelIndex& index) const
{
if(!index.isValid())
return root;
Node* parent = static_cast<Node*>(index.internalPointer());
int row = index.row();
return row>=0&&row<parent->children.count()?parent->children[index.row()]:0;
}
public:
Model(QObject* parent = 0)
: QAbstractItemModel(parent)
{
root = new Node;
root->parent = 0;
for(int i=1;i<=2;++i){
Node* node = new Node;
node->name = tr("Node %1").arg(i);
node->parent = root;
root->children.append(node);
}
}
void recurseDeleteChildren(Node* node)
{
for(int i=node->children.count()-1;i>=0;--i)
recurseDeleteChildren(node->children[i]);
delete node;
}
~Model()
{
recurseDeleteChildren(root);
}
QModelIndex index(int row,int column,const QModelIndex& parent) const
{
Node* node = nodeFromIndex(parent);
if(node&&row>=0&&row<node->children.count())
return createIndex(row,column,node);
return QModelIndex();
}
QModelIndex parent(const QModelIndex& index) const
{
Node* node = nodeFromIndex(index);
if(node&&node!=root){
Node* parent = node->parent;
if(parent!=root){
Node* grandParent = parent->parent;
return createIndex(grandParent->children.indexOf(parent),0,grandParent);
}
}
return QModelIndex();
}
int rowCount(const QModelIndex& index) const
{
Node* node = nodeFromIndex(index);
return node?node->children.count():0;
}
int columnCount(const QModelIndex& index) const
{
return 1;
}
QVariant data(const QModelIndex& index,int role) const
{
if(role==Qt::DisplayRole){
Node* node = nodeFromIndex(index);
if(node)
return node->name;
}
return QVariant();
}
void moveItem()
{
// Make first item a child of second item
bool ok = beginMoveRows(
QModelIndex(), // Moving child of root
0, // range from first child
0, // to (same) first child, inclusive
index(1,0,QModelIndex()), // destination is second child of root
0 // destination index is first child
);
Q_ASSERT(ok);
Node* newParent = root->children[1];
Node* movedNode = root->children.takeAt(0);
movedNode->parent = newParent;
newParent->children.append(movedNode);
endMoveRows();
}
};
class MainWindow : public QWidget
{
Q_OBJECT
private:
Model* model;
private slots:
void buttonClicked()
{
model->moveItem();
}
public:
MainWindow()
{
QVBoxLayout* layout = new QVBoxLayout(this);
QTreeView* view = new QTreeView;
model = new Model(this);
view->setModel(model);
view->setHeaderHidden(true);
layout->addWidget(view);
QPushButton* button = new QPushButton(tr("Move item"));
connect(button,SIGNAL(clicked(bool)),SLOT(buttonClicked()));
layout->addWidget(button);
}
};
int main(int argc,char* argv[])
{
QApplication a(argc,argv);
MainWindow wnd;
wnd.show();
return a.exec();
}
//-------------------------------------------------------------------------
That is, in a model with two elements being children of the root, I'm trying
to move the first child to become a child of second element.
beginMoveRows() returns true, but inside endMoveRows(), when it seems to be
fixing up persistent model indexes, it calls back
Model::index(row = 0,column = 0,index = { row = 1, column = 0, pointer = root node }),
where index appears to refer to the second child, where it was before move took place,
but since this index is now invalid, an invalid QModelIndex is returned and a warning
message is printed:
QAbstractItemModel::endMoveRows: Invalid index ( 0 , 0 ) in model Model(0xcba8e0)
While the view displays changed model correctly, application crashes upon termination.
Thanks in advance.
Pavel
More information about the Qt-interest-old
mailing list