Problem: I have a simple QStringListModel that I want to display in a view. However, I want each item in the view to be a custom QWidget that I have created. I do not understand why this is such a difficult problem! I have scoured the internet for solutions and, although I find bits and pieces here and there, no good solution fits all my needs.
The basic code for setting up my model/view:
QStringList strings;
// add some strings to the model
QStringListModel* model = new QStringListModel(strings);
QListView* view = new QListView;
view->setModel(model);
I have tried various attempts at doing this to no avail.
Attempt #1
I tried subclassing a new QItemDelegate object. Inside this object, I overrode the methods for creating an editor. I followed all the steps for setting up that delegate. The problem is that when the view is populated with the model, it grabs each item in the model in Qt::DisplayRole when I need it to grab each item in Qt::EditRole.
Attempt #2
Another method I tried was to subclass a QListView, and override the setModel method to call setIndexWidget for each item in the model. My code looks something this:
void CustomListView::setModel(QAbstractItemModel* model)
{
QListView::setModel(model);
for (int i = 0; i rowCount(); ++i)
{
QModelIndex index = model->index(i, 0);
CustomWidget* widget = new CustomWidget;
setIndexWidget(index, widget);
}
}
This worked as far as adding my CustomWidget object to each row in the list view. In order to ensure that the regular model data was not also shown beneath my CustomWidget objects, I also overrode CustomListView::paintEvent(QPaintEvent* event) to do nothing. Again, this worked.
But my major issue now is that when the list is displayed, although my CustomWidgets are displayed on it properly, the background of the list is a solid white color. I tried calling setAutoFillBackground(false) on the CustomListView but that di开发者_StackOverflow中文版d nothing. I want my list view to have a transparent background.
Any feedback on this problem would be greatly appreciated. I have spent a lot of time trying to get this to work! Thanks!
I think I had a problem similar for rendering custom data in a QStandardItemModel. What I did to solve it was to create a custom QStyledItemDelegate. In the createEditor method, you can test:
if( qVariantCanConvert<YourObject>(index.data(Qt::YourRole)) )
Then create your editor which is actually the custom widget you want. And set its value with data from your model. To customize my widget I used stylesheets like CustomWidget.setStylesheet("background: blue");
In the paint method of your delegate if you want the same widget you do exactly like you did with the editor.
CustomWidget renderer;
renderer.setText( index.data(Qt::DisplayRole).toString() );
renderer.resize(option.rect.size());
painter->save();
painter->translate(option.rect.topLeft());
renderer.render(painter);
painter->restore();
You'll have to handle yourself the openPersistentEditor and closePersistentEditor.
Hope it will help.
My suggestion is to stick to delegates with custom painting.
See the Star Delegate Example Like this you paint (see below) the way you want and then edit with createEditor
when you get the focus.
void StarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if (qVariantCanConvert<StarRating>(index.data())) {
StarRating starRating = qVariantValue<StarRating>(index.data());
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
starRating.paint(painter, option.rect, option.palette,
StarRating::ReadOnly);
} else {
QStyledItemDelegate::paint(painter, option, index);
}
}
The catch or the cheat is that you can paint your widget without creating an editor instance or having your widget in edit mode using drawControl()
. See the paint code in this question.
精彩评论