PDA

View Full Version : Custom delegate and event management



laugusti
9th September 2009, 13:24
Hi all,

I need some inputs to handle event in a delegate class.

I do have a tree view with a delegate where I overrided QAbstractItemDelegate::editorEvent() in order to implement specific behaviors. This tree supports multiple selection.
The cells contains text and icons.

Now, when the user clicks an icon, I would like to be able to retrieve the selected rows to enable/disable this icon for all those selected rows (see attached screenshot).

As a solution, I thought about doing it in the QAbstractItemDelegate::editorEvent() method, but I don't know how to retrieve the selected rows in the delegate? Maybe it's not possible? Maybe it's the way to do it?

Did somebody have any clue?

Regards,
Lionel

victor.fernandez
9th September 2009, 17:48
You could reimplement paint() and check whether the row is selected or not and paint the icon or not. In order to find out if a row is selected, you can use (option.state() & QStyle::State_Selected).

faldzip
9th September 2009, 19:10
selection model is something you are looking for I guess :] But you have to have a view, not a model, for that. As i found in Qt Creator (or Qt) sources, the trolls got the view by QStyleOptionViewItemV3 (hmm i guess it was V3 but not sure). There is one public undocumented member of type QWidget *. Try qobject_cast'ing it to the type of your view. This should work, but doesn't have to. From view you can get QSelectionModel with selectionModel() method.
Another solution would be to just emit some signal whenever there is a situation that require icon change, and connect some slot to it which would be somewhere, where you have direct access to your view, so you can easily get selection model

wysota
9th September 2009, 22:33
Guys, don't overcomplicate things. This is not a task for a delegate, it's a task for the view or its environment. The delegate is responsible for handling one item only, it doesn't interconnect items together in any way. What you want is identical to the Qt::CheckState role in Qt's models. Provide an identical mechanism (involving all the view, delegate and the model) if you can't reuse the check state one. Then connect to the dataChanged() signal in the model (or a custom signal you will emit), track that the change was in this particular role and update the view accordingly. Alternatively implement that directly in the view, without touching the model (like the branching mechanism in QTreeView is implemented) - that would be an even better solution.

laugusti
10th September 2009, 10:09
Thank you all for your time and advices,

Wysota, you point my problem! I understood that my delegate must handle only one item so I didn't know how to manage actions on all selected items.
I'll go with your solution because it looks to be the natural way to do.

As I already enable/disable the icons depending on boolean values in the model, I guess I could solve my problem only by connecting the QAbstractItemModel::dataChanged() signal.
When I am notified, I can retrieve the selected items, check if the current item is part of the selection and then modified all selected items if so.

I'll keep you informed ...

Regards,
Lionel

laugusti
10th September 2009, 10:46
It brings another problem ... I have 4 TreeViews on 1 Model so I get notified 4 times on dataChanged().
First solution I see is to keep an internal flag to know when the user has really made a click. I can do it by using the mousePressEvent().
I think there is a better way to solve it.


The other problem I see is that I'll get notified on dataChanged(), then I'll update all selected items then get notified again ... and it will be an infinite loop.

Grrrr....

Regards,
Lionel

laugusti
10th September 2009, 14:19
I made it work ... however I am not sure it's a pretty solution.

1/ On the TreeView, I override QAbstractItemView::mouseReleaseEvent() so I can retrieve the list of selected rows. I give this list to the delegate then I call QAbstractItemView::mouseReleaseEvent() on the parent class.

2/ In the delegate class, I override QAbstractItemDelegate::editorEvent(). For the QEvent::MouseButtonRelease event, I check if the click hits an icon and then call a method itemClicked() on my proxy model with the given index and the list of selected rows I previously stored.

3/ In the method itemClicked() of the proxy model, I check if the index is part of the selection and update the value of the given index and all selected items.

I ran a few tests and it looks like it works but I need more tests to be sure.
I was also thinking about giving the list of selected rows directly to the proxy model so my delegate would only check the position of the mouse and then let the proxy model work on all selected items.

I still have a question if you don't mind ... When hitting an icons, I would like to keep the selection. For example, I have 3 items (1, 2, 3), I select 1 & 2 and I hit an icon on the 3rd item, I would like to keep 1 & 2 as the selected items.
I tried to do it in the QAbstractItemDelegate::editorEvent() and it works when I hit an icon for a non-selected item. But when I hit an icon for an item which is a part of the selection, this particular item is the only one selected afterwards.

Regards,
Lionel