Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

qt

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?

like image 445
JasonGenX Avatar asked Mar 29 '11 17:03

JasonGenX


1 Answers

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);
}
like image 108
Dave Mateer Avatar answered Jan 02 '23 06:01

Dave Mateer