PDA

View Full Version : Custom model with a QTreeView... I don't understand how to add drag&drop support



javimoya
7th January 2011, 09:58
Hi !
I have a treeview with a custom model (read only) working perfectly...
but now I want to implement drag&drop support (but only inside the treeview! not to other widgets or from other widgets)

I have read all the documentation and books... but I think that I don't understand it well.

This is only a simplified example to expose my doubts and questions about that.

Important Note: The treeview cannot be edited by user.
(I can change de model programatically... but not directly in the view)

These are my classes:


class Teacher
{
...
...
private:
QString m_name; // this will be a column in the treeview
QString m_phone; // this will be a column in the treeview
School * m_school // "parent" school of the teacher
// much more complex data that is not going to be showed in the treeview
QPicture m_photo;
MyOtherDataTeacher m_otherData;
etc
...
...
}

class School
{
...
...
private:
QString m_name; // this will be a column in the treeview
QString m_address; // this will be a column in the treeview
// much more complex data that is not going to be showed in the treeview
QDate m_openingDate;
MyOtherDataSchool m_otherData;
etc
...
...
}

class SchoolTeacherModel : public QAbstractItemModel
{
...
...
private:
QList<School *> m_schools; // each school will be a "top level item" in the treeview
QList<Teacher *> m_teachers; // each teacher will be a child of his school
// the model contains other data not needed by the view
QDate m_whateverdate;
MyOtherData m_whatever;
etc
...
...
}

[First step]
With that data model I want to create a read-only tree like this:

+ School1 street A, 3-3

teacher1 555-644-247
teacher2 555-641-577
+ School2 street B, 4-3

teacher3 555-644-247
teacher4 555-641-577
+ School3 street C, 2-6

(under each school we can see their teachers)

That's pretty easy...
I only need to reimplement these methods in SchoolTeacherModel:

QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
Everything very easy...
Note that my "columnCount(...)" method is implemented in this way:

int SchoolTeacherModel::columnCount(const QModelIndex &parent) const
{
return 2; // because this is the max number of columns that is going to be showed
}
And that "data(...)" is implemented in this way (a bit simplified for brevity):

QVariant SchoolTeacherModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
{
return QVariant();
}

if (role != Qt::DisplayRole)
{
return QVariant();
}

// Important Note: I only support here data that is to be shown... but remember that internally School and Teacher has much more data that the view doesnt need...
if (index.isSchool()) // <- this is a simplification
{
School * school = static_cast<School*>(index.internalPointer());
switch (index.column)
{
case 0:
return school->m_name; break;
case 1:
return school->m_address; break;
default:
return QVariant();
}
}
else if (index.isTeacher()) // <- this is a simplification
{
Teacher * teacher = static_cast<Teacher*>(index.internalPointer());
switch (index.column)
{
case 0:
return teacher->m_name; break;
case 1:
return teacher->m_phone; break;
default:
return QVariant();
}
}
return QVariant();
}

That is my read-only model...
and it is working perfectly. And I think that is corretcly implemented. (do you agree? or do you think that my columnCount(...) and data(...) are not correct?)

In my imaginary window I have a button... "Create school with teachers"... (Insert a new school in my model)
So in my model added this imaginary method:


void SchoolTeacherModel::insertSchool(School * school)
{
beginInsertRows(QModelIndex(),m_schools.count(),m_ schools.count());
m_schools.insertItem(m_schools.count(), school);
endInsertRows();
}

This is working perfectly too. Now I can add new schools programatically.
Note: I have not reimplemented these methods ->

bool QAbstractItemModel::insertRows ( int row, int count, const QModelIndex & parent = QModelIndex() );
bool QAbstractItemModel::setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole )
For the moment I don't need them ! (correct?)

[Second step]
Now I want to add support for "drag and drop" rows of the treeview
(only drag and drop INSIDE the treeview... I only want that the user can move -for example- Teacher1 from School1 to School2. I don't want support for drad&drop to/from other widgets)

What methods should I reimplement?

Qt::DropActions DragDropListModel::supportedDropActions() const -> YES (move action)
Qt::ItemFlags DragDropListModel::flags(const QModelIndex &index) const -> YES
QStringList DragDropListModel::mimeTypes() const -> Not sure !
QMimeData *DragDropListModel::mimeData(const QModelIndexList &indexes) const -> Not sure !
bool DragDropListModel::dropMimeData(const QMimeData *data,
Qt::DropAction action, int row, int column, const QModelIndex &parent) -> Not sure !
QAbstractItemModel::removeRows(...) -> Not sure !!
bool QAbstractItemModel::insertRows(...) -> Not sure !!
bool QAbstractItemModel::setData(...) -> Not sure !! and... how?? only columns that are going to be showed? or all the data??
....
I need to reimplement any other method???
....
and...
Do I need to change my columnCount(...) and data(...) methods???
For the moment, remember, they only "see" data that is going to be showed (name and address in School, and name a phone in Teacher)... but they don't see all the rest of data that is inside school and teacher classes.

Of course i added this:
myTreeView->setDragEnabled(TRUE);
myTreeView->setAcceptDrops(TRUE);
myTreeView->setDropIndicatorShown(TRUE);
myTreeView->setSelectionBehavior(QAbstractItemView::SelectRows );

another side question:
I don't like how the drop indicator looks...is possible to alter it??

Thank you very much.

javimoya
8th January 2011, 12:04
any help?:rolleyes:
I have seen this easy solution:
http://www.qtcentre.org/threads/10454-whole-row-drag-drop?p=55291#post55291
but it doesn't work !
in tha example if you drag the first column... it works perfectly...
but if you drag the second column... it create 2 rows !!!!
:confused: