JasonGenX
JasonGenX

Reputation: 5434

Qt: Clickable 'buttons' on each row custom painted with QAbstractItemDelegate

I'd like to draw 'clickable' icons (or buttons) on each row of a QListView I'm using my own custom "QAbstractItemDelegate" derived class to paint. Those buttons may change with the custom status of the row (i have access to the underlying data structure during painting).

What's the best way to approach this?

Upvotes: 9

Views: 4065

Answers (1)

Dave Mateer
Dave Mateer

Reputation: 17946

DISCLAIMER: This may not be the best way, but here is a way where you have full control. We found it necessary to do this with drawing check boxes.

You can inherit from QStyledItemDelegate (or QAbstractItemDelegate may work .. have not tried it) and reimplement the paint and editorEvent methods. You use QStyle::drawControl() (after setting the appropriate style options) to draw the control in paint, and then manually test for a mouse hit in the editorEvent and do something with it. If memory serves me correctly, this code was largely inspired (cough, copied, cough, cough) from looking at the Qt source code for the QStyledItemDelegate.

void CheckBoxDelegate::paint(QPainter *painter,
                             const QStyleOptionViewItem &option,
                             const QModelIndex &index) const {
  bool checked = index.model()->data(index, Qt::DisplayRole).toBool();

  if (option.state & QStyle::State_Selected) {
    painter->setPen(QPen(Qt::NoPen));
    if (option.state & QStyle::State_Active) {
      painter->setBrush(QBrush(QPalette().highlight()));
    }
    else {
      painter->setBrush(QBrush(QPalette().color(QPalette::Inactive,
                                                QPalette::Highlight)));
    }
    painter->drawRect(option.rect);
  }

 QStyleOptionButton check_box_style_option;
  check_box_style_option.state |= QStyle::State_Enabled;
  if (checked) {
    check_box_style_option.state |= QStyle::State_On;
  } else {
    check_box_style_option.state |= QStyle::State_Off;
  }
  check_box_style_option.rect = CheckBoxRect(option);

  QApplication::style()->drawControl(QStyle::CE_CheckBox,
                                     &check_box_style_option,
                                     painter);
}

bool CheckBoxDelegate::editorEvent(QEvent *event,
                                   QAbstractItemModel *model,
                                   const QStyleOptionViewItem &option,
                                   const QModelIndex &index) {
  if ((event->type() == QEvent::MouseButtonRelease) ||
      (event->type() == QEvent::MouseButtonDblClick)) {
    QMouseEvent *mouse_event = static_cast<QMouseEvent*>(event);
    if (mouse_event->button() != Qt::LeftButton ||
        !CheckBoxRect(option).contains(mouse_event->pos())) {
      return true;
    }
    if (event->type() == QEvent::MouseButtonDblClick) {
      return true;
    }
  } else if (event->type() == QEvent::KeyPress) {
    if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space &&
        static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select) {
      return false;
    }
  } else {
    return false;
  }

  bool checked = model->data(index, Qt::DisplayRole).toBool();
  return model->setData(index, !checked, Qt::EditRole);
}

Upvotes: 7

Related Questions