Cherubim
Cherubim

Reputation: 55

QStandardItemModel header with widget and text

i need to use checkbox with text, like this "Check all":

enter image description here

in header of QStanndardItemModel. I tried like this

QStandardItem* item0 = new QStandardItem("some text");
item0->setCheckable(true);
item0->setCheckState(Qt::Checked);
item0->setText("some text");

_model->setHorizontalHeaderItem(1, item0);

This way only works for items not for header, i mean for items if i use

_model->setItem(new QStandardItem(some_item);

I heard about writing my own class which inherit QHeaderView but i dont know if this can help in my problem. I would ask if there is a easy way to achieve this?

Regards

Upvotes: 1

Views: 4394

Answers (2)

Cherubim
Cherubim

Reputation: 55


i did something like this:

QStandardItemModel *model = new QStandardItemModel(this);

ui->tableView->setModel(model);

QtCheckHeaderView *header = new QtCheckHeaderView(Qt::Horizontal, ui->tableView);


QtCheckHeaderView *vheader = new QtCheckHeaderView(Qt::Vertical, ui->tableView);

ui->tableView->setHorizontalHeader(header);
ui->tableView->setVerticalHeader(vheader);

QStandardItem *root = model->invisibleRootItem();
QList<QList<QStandardItem *> > items;
for (int i = 0; i < 10; ++i)
{
    QList<QStandardItem *> res;
    for (int j = 0; j < 1000; ++j)
    {
        res.append(new QStandardItem(QString("%1;%2").arg(j).arg(i)));
        vheader->addCheckable(j);
    }
    items.append(res);
    root->appendColumn(res);

    header->addCheckable(i);
}

this works great. Draws checkbox with text in vertical and horizontal header. But this works great only if i put this code to MainWindow constructor. If i put this code to for example pushbutton function this wont work. Datas are fine but headers are invisible.

ui->tableView->repaint();

wont work. Someone maybe knows the answer why this is happening and/or how to solve this? thanks for answer

Upvotes: 1

Pavel Strakhov
Pavel Strakhov

Reputation: 40492

Qt models don't support item flags for headers. Setting item flags on items that are used as headers has no effect. QHeaderView doesn't support drawing checkboxes. I'm afraid subclassing QHeaderView is the simpliest way.

I wrote an example of how it can be implemented based on this FAQ page. This class assumes that you use QStandardItemModel and uses flags of its header items. If someone would want to use other model class, subclassing QAbstractItemModel and implementing missing interface and changing headerview implementation would be needed.

class MyHeader : public QHeaderView
{
public:
  MyHeader(Qt::Orientation orientation, QWidget * parent = 0);

protected:
  QStandardItemModel* standard_model;
  virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
  virtual void mousePressEvent(QMouseEvent *event);
  virtual void setModel(QAbstractItemModel* model);

};

MyHeader::MyHeader(Qt::Orientation orientation, QWidget *parent) : QHeaderView(orientation, parent)
{
  standard_model = 0;
}

void MyHeader::paintSection(QPainter *painter, const QRect &rect, int logical_index) const {
  painter->save();
  QHeaderView::paintSection(painter, rect, logical_index);
  painter->restore();
  if (standard_model && orientation() == Qt::Horizontal) {
    QStandardItem* item = standard_model->horizontalHeaderItem(logical_index);
    if (item && item->isCheckable()) {
      int offset = (height() - style()->pixelMetric(QStyle::PM_IndicatorHeight))/2;
      int pos = sectionViewportPosition(logical_index);
      QStyleOptionButton option;
      option.rect = QRect(offset + pos, offset,
                          style()->pixelMetric(QStyle::PM_IndicatorWidth),
                          style()->pixelMetric(QStyle::PM_IndicatorHeight));
      if (item->checkState() == Qt::Checked) {
        option.state = QStyle::State_On;
      } else {
        option.state = QStyle::State_Off;
      }
      option.state |= QStyle::State_Enabled;
      style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
    }
  }
}

void MyHeader::mousePressEvent(QMouseEvent *event) {
  int offset = (height() - style()->pixelMetric(QStyle::PM_IndicatorHeight))/2;
  if (standard_model && orientation() == Qt::Horizontal) {
    for(int logical_index = 0; logical_index < count(); logical_index++) {
      int pos = sectionViewportPosition(logical_index);
      QRect rect(offset + pos, offset,
                 style()->pixelMetric(QStyle::PM_IndicatorWidth),
                 style()->pixelMetric(QStyle::PM_IndicatorHeight));
      if (rect.contains(event->pos())) {
        QStandardItem* item = standard_model->horizontalHeaderItem(logical_index);
        if (item && item->isCheckable()) {
          item->setCheckState(item->checkState() == Qt::Checked ? Qt::Unchecked : Qt::Checked);
          return;
        }
      }
    }
  }
  QHeaderView::mousePressEvent(event);
}

void MyHeader::setModel(QAbstractItemModel *model) {
  QHeaderView::setModel(model);
  standard_model = qobject_cast<QStandardItemModel*>(model);
}

//usage
QTableView  view;
QStandardItemModel model;
model.setColumnCount(5);
QStandardItem* item0 = new QStandardItem("some text");
item0->setCheckable(true);
item0->setCheckState(Qt::Checked);
item0->setText("some text");
model.setHorizontalHeaderItem(0, item0);
view.setModel(&model);
MyHeader *myHeader = new MyHeader(Qt::Horizontal, &view);
view.setHorizontalHeader(myHeader);
view.show();

Upvotes: 0

Related Questions