views:

1161

answers:

1

Hi, everyone!

I am a noob in using model/view paradigm in Qt and have the following problem: I have a tree-like structure, that must be visualized via Qt. I found out, that QAbstractTableModel is perfect for my needs, so I write the following:

class columnViewModel : public QAbstractTableModel {
   // some stuff...
};

Everything now works, but now I have to implement an "Observer" design pattern over the nodes of my tree. Whenever the node expands in the TreeView, I must add an Observer to the corresponding node. Whenever the node collapses, I must remove this Observer from the node. So, I write something, like this:

void onExpand( const QModelIndex & Index ... ) {
   Node* myNode = static_cast<Node*>(Index->internalPointer());
   Observer* foo = Observer::create();
   myNode->addObserver(foo);

   // ok up to here, but now where can I save this Observer? I must associate 
   // it with the Node, but I cannot change the Node class. Is there any way 
   // to save it within the index?
}

void onCollapse( const QModelIndex & Index ... ) {
   Node* myNode = static_cast<Node*>Index->internalPointer();
   Observer* foo = // well, what should I write here? Node does not have anything 
                   // like "getObserver()"! Can I extract an Observer from Index?

   myNode->remObserver( foo );
}

I don't have the snippets right now, so the code may be not a valid Qt, but the problem seems clear. I can change neither Node nor Observer classes. I can have a inner list of Observers, but then I have to resolve, what Observer to remove from the specific node. Is there any way to save the Observer pointer within Index (some user data maybe), to resolve it quickly in onCollapse? Any ideas would be welcome...

+3  A: 

Do the following:

  • Define a new role (similar to Qt::UserRole), let's say ObserverRole.
  • Use QAbstractItemModel::setData to set the observer as data with observer role. The code sketch:

    this->model()->setData( ObserverRole, QVariant::fromValue( foo));

  • You might need to put in the cpp implementation file a declaration for metadata, something like

    Q__DECLARE __METATYPE ( Observer* );

to allow QVariant to make the variant casts in a proper way.

  • You can get the observer for an index using QModelIndex::data with Observer role:

    index.data( ObserverRole);

  • In your model implementation, add support for returning data for Observer role, if any (as you probably did for Qt::UserRole or Qt::DisplayRole.

Update on received comment:

Normally, the QModelIndex::data gives the data for the viewer. The role specified when asking for data allows the customizer of the model to provide different data for different reasons (e.g. provide a string for display role -> the title of the item).

If you don't use this mechanism for getting the data, then you probably don't need QTreeView. In this case, use QTreeWidget, where you can work directly with QTreeWidgetItems and to attach data to the item through setData method, or to subclass QTreeWidgetItem and add the data as member of that subclass.

The views are usually used when you want to work with models.

Cătălin Pitiș
That sounds like the solution, but I have problems, implementing the final part. Whenever I define Qt::DisplayRole, I take internalPointer() from the Index, which is actually, a Node. When I define ObserverRole, I cannot use internalPointer() anyway, and now I think, I must switch to some struct {}, where to keep both Node and its Observer. I will be able to typecast index internalPointer() to that struct or so...
See the update I've just added.
Cătălin Pitiș
Thanks for the ideas. I understood right now, that it is not the problem of Qt models, instead it is a problem of my Observer / Node paradigm. I should do some coding to create a hash, that will allow me to resolve what observer belongs to a particular node.