Michael Hasselmann

How to customize your view with delegates

The usual way in Qt, when an item view wants to render itself, is to ask the item model for everything, layout, style and the actual data. Storing view-specific layout information in the model itself means that views and models can always only exist in a 1:1 relationship. The logical conclusion: If you need to share a model between different views, you will probably have to add proxy models for each view. I wasn't satisfied with that idea, so I continued to research QStyledItemDelegates. They have the following nice properties:

  1. They are owned by the view.
  2. They have complete control over the cell they are assigned to (although that might not be too obvious).
  3. They only get called if there's work to do, that is, nothing is wasted unless a cell becomes visible in a view.

So instead of having one proxy model per view, I can now keep the single model/multiple views approach by writing custom delegates for each view. For a tabular view, that means I want to install custom delegates per column or row (see Qlom's main window implementation).

How to change colors of a cell

Use the delegate's paint method, apply your changes to the QStyleOptionViewItem's palette and forward the paint request to the parent class. I had problems getting the correct background role, that is why I simply used the supplied painter to draw the background myself.

How to format data from the model in the view

The delegates' displayText method comes in handy. The model's data is wrapped in a QVariant already, so your custom delegate can apply all kinds of string formatting here. Just be aware that this method will never be called if the QVariant returned from the model (for the queried model index) is null.

How to replace a cell with a custom widget

For this, we abuse the fact that delegates are owned by their view. We only need to find a method that has a model index parameter, e.g., the paint method, and we are good to go! Inside that method, we query the parent() and use the item view's setIndexWidget method (perhaps check if there already is a widget at the given index, so that we don't end up re-creating widgets for every paint request).

In Qlom, the embedded widget is a simple button, so I was interested in its pressed signal. For that, I used a QSignalMapper to bind custom data (here: the model index) to the delegate's buttonPressed signal. Now the view can connect to the delegates' buttonPressed signal, unwrap the custom QObject to find the model index and display a nice message box with the exact model index of the clicked button.

Feedback and especially corrections welcome!

Comments

No comments yet.

Post a Comment

Optional: Only needed, if you wish to subscribe.