August 26, 2011

Frank Thomas Frank Thomas
Lab Rat
4 posts

[Solved] QListWidget for displaying items in QTableView’s cells

 

Hi,

I’m trying to use QListWidgets to display QStringLists in the cells of a QTableView. To do so, I subclassed QStyledItemDelegate and render the QListWidget in the paint() method. This works fine so far, the only problem I have is, that option.rect.topLeft() in paint(…, const QStyleOptionViewItem& option, …) does not correspond to the top left corner of the corresponding cell. It seems to be off by the dimensions of the top left header cell, as this screenshot suggests:

screenshot

So my question is: how do I get the right coordinates for correctly rendering the QListWidgets in QTableView’s cells? Working example code is below.

Thanks,
Frank

MultipleSelectDelegate.h:

  1. #ifndef MULTIPLESELECTDELEGATE_H
  2. #define MULTIPLESELECTDELEGATE_H
  3.  
  4. #include <QStyledItemDelegate>
  5.  
  6. class MultipleSelectDelegate : public QStyledItemDelegate {
  7.   Q_OBJECT
  8.  
  9.  public:
  10.   MultipleSelectDelegate(QObject* parent = 0);
  11.  
  12.   void paint(QPainter* painter, const QStyleOptionViewItem& option,
  13.              const QModelIndex& index) const;
  14.  
  15.   QSize sizeHint(const QStyleOptionViewItem& option,
  16.                  const QModelIndex& index) const;
  17. };
  18.  
  19. #endif // MULTIPLESELECTDELEGATE_H

MultipleSelectDelegate.cpp:

  1. #include "MultipleSelectDelegate.h"
  2. #include <QStyledItemDelegate>
  3. #include <QListWidget>
  4. #include <QStringList>
  5.  
  6. MultipleSelectDelegate::MultipleSelectDelegate(QObject* parent)
  7.   : QStyledItemDelegate(parent) {}
  8.  
  9. void MultipleSelectDelegate::paint(QPainter* painter,
  10.     const QStyleOptionViewItem& option, const QModelIndex& index) const {
  11.   QStringList list = index.data().toStringList();
  12.   QListWidget list_widget;
  13.   list_widget.addItems(list);
  14.   list_widget.render(painter, option.rect.topLeft());
  15. }
  16.  
  17. QSize MultipleSelectDelegate::sizeHint(const QStyleOptionViewItem& option,
  18.                                        const QModelIndex& index) const {
  19.   QStringList list = index.data().toStringList();
  20.   QListWidget list_widget;
  21.   list_widget.addItems(list);
  22.   return list_widget.sizeHint();
  23. }

TableModel.h:

  1. #ifndef TABLEMODEL_H
  2. #define TABLEMODEL_H
  3.  
  4. #include <QAbstractTableModel>
  5. #include <QModelIndex>
  6. #include <QList>
  7. #include <QObject>
  8. #include <QVariant>
  9.  
  10. class TableModel : public QAbstractTableModel {
  11.   Q_OBJECT
  12.  
  13.  public:
  14.   explicit TableModel(QObject* parent = 0);
  15.  
  16.   int rowCount(const QModelIndex&) const;
  17.  
  18.   int columnCount(const QModelIndex&) const;
  19.  
  20.   QVariant data(const QModelIndex& index, int role) const;
  21.  
  22.  private:
  23.   QList<QVariant> data_;
  24. };
  25.  
  26. #endif // TABLEMODEL_H

TableModel.cpp:

  1. #include "TableModel.h"
  2. #include <QStringList>
  3.  
  4. TableModel::TableModel(QObject* parent) : QAbstractTableModel(parent) {
  5.   QStringList list1, list2;
  6.   list1 << "one" << "two" << "three" << "four";
  7.   list2 << "1111" << "2222" << "3333" << "4444";
  8.   data_ << list1 << list2;
  9. }
  10.  
  11. int TableModel::rowCount(const QModelIndex&) const {
  12.   return data_.size();
  13. }
  14.  
  15. int TableModel::columnCount(const QModelIndex&) const {
  16.   return 1;
  17. }
  18.  
  19. QVariant TableModel::data(const QModelIndex& index, int role) const {
  20.   if (!index.isValid())
  21.     return QVariant();
  22.  
  23.   if (index.row() >= data_.size())
  24.     return QVariant();
  25.  
  26.   if (role == Qt::DisplayRole) {
  27.       return data_.at(index.row());
  28.   }
  29.   return QVariant();
  30. }

main.cpp:

  1. #include <QApplication>
  2. #include <QTableView>
  3. #include "MultipleSelectDelegate.h"
  4. #include "TableModel.h"
  5.  
  6. int main(int argc, char *argv[]) {
  7.   QApplication app(argc, argv);
  8.  
  9.   QTableView* table = new QTableView();
  10.   TableModel* model = new TableModel(table);
  11.   MultipleSelectDelegate* delegate = new MultipleSelectDelegate(table);
  12.   table->setModel(model);
  13.   table->setItemDelegate(delegate);
  14.   table->show();
  15.  
  16.   return app.exec();
  17. }

5 replies

August 26, 2011

Gerolf Gerolf
Robot Herder
3253 posts

I would not use a real listwidget fopr rendering.
My proposal would be: look at the code of the list widget and do the same.
But if you really want to use render, don’t use topLeft as offset. I am pretty sure, that is your problem…

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

August 27, 2011

Andre Andre
Robot Herder
6395 posts

That would end up being recursive :-) QListWidget is a subclass of QListView, which uses delegates like all the views.

August 28, 2011

Volker Volker
Ant Farmer
5428 posts

Do you need the list widget for some functionality or do you just use it to “ease” the display of the string list? If you do the latter, there surely would be more elegant and efficient ways to do this.

As a first thought, I would try to change the data() method of your model and have it return a string for the Qt::DisplayRole:

  1. QVariant MyModel::data(const QModelIndex &index, int role)
  2. {
  3.     if(role == Qt::DisplayRole) {
  4.         return theStringList.join("\n");
  5.     } else {
  6.         // your other role code here....
  7.     }
  8. }

The standard delegates handle multiline text.

August 28, 2011

Frank Thomas Frank Thomas
Lab Rat
4 posts

Just to explain why I’ve choosen a QListWidget for displaying a list of strings: My final goal is to implement an item delegate for multiple selection of objects in a list. If the list is displayed some items of it should be selected and when the user edits the cell it should be possible to select other items or deselect already selected items. I thought the easiest way to accomplish a multiple select delegate is to use a QListWidget for displaying and editing the selections.

August 29, 2011

Frank Thomas Frank Thomas
Lab Rat
4 posts

I found a solution for my problem by looking again at the Star Delegate Example [doc.qt.nokia.com]. Instead of calling render(…) with option.rect.topLeft() as offset, translating painter with option.rect.topLeft() before calling render(…) fixes my problem:

  1. list_widget.render(painter, option.rect.topLeft());

  1. painter->translate(option.rect.topLeft());
  2. list_widget.render(painter);

So apparently I didn’t understand what the effect of calling QWidget::render(…) with a targetOffset [doc.qt.nokia.com] means.

Thanks again for all your input.

 
  ‹‹ Delete stretches from layout      [Solved] Updating the underlying data without using the QAbstractItemModel::setData() method. ››

You must log in to post a reply. Not a member yet? Register here!