PDA

View Full Version : QStyledItemDelegate events are not called



PinTxO
13th October 2015, 16:51
Hi everyone.

This is my first post in this comunity and hopefully not the last.

My problem is the next, I've created a custom delegated for a QComboBox but I don't see the items, I mean, when I click in the combo I can see deployed items but not the information(a image with a text and two more images). Debugging I've noticed that the paint event never is called. The curious thing is that the info in the items exists because when I click one of them, the info shows in the combo. My code:

delegates.h

class ComboUpDownDelegate : public QStyledItemDelegate {
Q_OBJECT

public:
static const int SESSION_DATA_ROLE;
static const int ICON1_ROLE;
static const int ICON2_ROLE;
static const int ICON3_ROLE;

static const char* COMBO_TYPE;
static const QString COMBO_ICON_TEXT;
static const QString COMBO_ICON_TEXT_ICONS;
static const QString COMBO_ICON_RICHTEXT_COUNTER;

public:
ComboUpDownDelegate(QObject* parent);
~ComboUpDownDelegate();

void initCombo(QComboBox* combo);

virtual QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const override;
virtual void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
virtual bool eventFilter(QObject *object, QEvent *event) override;

void setTitle(const QString& title);
QString title() const;

virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override {
return nullptr;
}

protected:
void drawIconRichTextCounter(QPainter* painter, const CUDSession& data, const QPoint& topLeft, int row, int width) const;

private:
QString m_title;
QPixmap m_icon1, m_icon2, m_icon3;
};


delegates.cpp

namespace {
QPoint drawText(QPainter* painter, const QPoint& point, const QString& text, const QFont& font) {
painter->setFont(font);

QFontMetrics fm(font);
const int w = fm.width(text);
painter->drawText(point, text);

return QPoint(point.x() + w, point.y());
}
}

const int ComboUpDownDelegate::SESSION_DATA_ROLE = Qt::UserRole + 1;
const int ComboUpDownDelegate::ICON1_ROLE = Qt::UserRole + 1;
const int ComboUpDownDelegate::ICON2_ROLE = Qt::UserRole + 2;
const int ComboUpDownDelegate::ICON3_ROLE = Qt::UserRole + 3;

const char* ComboUpDownDelegate::COMBO_TYPE = "combo_type";
const QString ComboUpDownDelegate::COMBO_ICON_TEXT = "icon_text";
const QString ComboUpDownDelegate::COMBO_ICON_TEXT_ICONS = "icon_text_icons";
const QString ComboUpDownDelegate::COMBO_ICON_RICHTEXT_COUNTER = "icon_richtext_counter";

ComboUpDownDelegate::ComboUpDownDelegate(QObject* parent)
: QStyledItemDelegate(parent) {
initCombo(qobject_cast<QComboBox*>(parent));

// Icons
m_icon1 = Customisation::getImage("time", QSize(16, 16), QColor("#C8C8C8"));
m_icon2 = Customisation::getImage("warning", QSize(16, 16), QColor("#C8C8C8"));
m_icon3 = Customisation::getImage("warning", QSize(16, 16), QColor("#FF0000"));
}

ComboUpDownDelegate::~ComboUpDownDelegate() {
}

void ComboUpDownDelegate::initCombo(QComboBox* combo) {
if (combo != nullptr) {
combo->view()->setEditTriggers(QAbstractItemView::CurrentChanged) ;
combo->installEventFilter(this);
}
}

QSize ComboUpDownDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const {
auto combo = static_cast<QComboBox*>(this->parent());

const auto text = index.data(Qt::DisplayRole).toString();
const auto style = QApplication::style();

QStyleOptionButton opt;
opt.text = text;
opt.rect = option.rect;
opt.icon = index.data(Qt::DecorationRole).value<QIcon>();
if (combo != nullptr) {
opt.iconSize = combo->iconSize();
}

return style->sizeFromContents(QStyle::CT_CheckBox, &opt, QSize());
//return style->sizeFromContents(QStyle::CT_PushButton, &opt, QSize());
}

void ComboUpDownDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const {
QComboBox* combo = static_cast<QComboBox*>(this->parent());

// Basic style
QStyleOptionViewItemV4 modifiedOption(option);
modifiedOption.text.clear();
modifiedOption.icon = QIcon();
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &modifiedOption, painter);

const auto topLeft = option.rect.topLeft();
const int margin = 3;
const int fontHeight = QFontMetrics(painter->font()).height();

painter->setPen(combo->palette().color(QPalette::Text));

if (combo->property(COMBO_TYPE) == COMBO_ICON_TEXT)
{
const bool state1 = index.data(ICON1_ROLE).toBool();
QPixmap icon1(state1 ? m_icon1 : m_icon2);
painter->drawPixmap(margin, topLeft.y() + margin, icon1);

const QString text = index.data(Qt::DisplayRole).toString();
painter->drawText(icon1.width() + 2 * margin, topLeft.y() + fontHeight + 3, text);

const bool state2 = index.data(ICON2_ROLE).toBool();
QPixmap icon2(state2 ? m_icon1 : m_icon2);
int w = option.rect.width() - icon2.width() - margin;
painter->drawPixmap(w, topLeft.y() + margin, icon2);
}
else if (combo->property(COMBO_TYPE) == COMBO_ICON_TEXT_ICONS)
{
const bool state1 = index.data(ICON1_ROLE).toBool();
QPixmap icon1(state1 ? m_icon1 : m_icon2);
painter->drawPixmap(margin, topLeft.y() + margin, icon1);

const QString text = index.data(Qt::DisplayRole).toString();
painter->drawText(icon1.width() + 2 * margin, topLeft.y() + fontHeight + 3, text);

const bool state3 = index.data(ICON3_ROLE).toBool();
QPixmap icon3(state3 ? m_icon1 : m_icon2);
int w = option.rect.width() - icon3.width() - margin;
painter->drawPixmap(w, topLeft.y() + margin, icon3);

const bool state2 = index.data(ICON2_ROLE).toBool();
QPixmap icon2(state2 ? m_icon1 : m_icon2);
w -= icon2.width();
painter->drawPixmap(w, topLeft.y() + margin, icon2);
}
else if (combo->property(COMBO_TYPE) == COMBO_ICON_RICHTEXT_COUNTER)
{
const CUDSession data = index.data(SESSION_DATA_ROLE).value<CUDSession>();
drawIconRichTextCounter(painter, data, topLeft, index.row(), option.rect.width());
}
}

void ComboUpDownDelegate::drawIconRichTextCounter(QPain ter* painter, const CUDSession& data, const QPoint& topLeft, int row, int width) const {
const int margin = 15;

QPixmap icon1(m_icon1);
painter->drawPixmap(margin, topLeft.y() + margin, icon1);

QFont normalFont(painter->font());
QFont boldFont(normalFont);
boldFont.setBold(true);
QFontMetrics fm(normalFont);

QPoint p(topLeft + QPoint(icon1.width() + 1.5 * margin, fm.height() + 11));
if (row == 0)
{
p = drawText(painter, p, QString("ALL SESSIONS"), boldFont);
}
else
{
QString strRow = QString::number(row);
if(strRow.length() < 2)
{
strRow = "0" + strRow;
}
p = drawText(painter, p, QString("SESSION %1").arg(strRow), boldFont);
painter->setPen(QColor("#C8C8C8"));
p = drawText(painter, p, QString(" | "), normalFont);
p = drawText(painter, p, QString("START:"), boldFont);
p = drawText(painter, p, QString(" %1 - ").arg(data.StartStr()), normalFont);
p = drawText(painter, p, QString("END:"), boldFont);
if(data.End().isValid())
{
p = drawText(painter, p, QString(" %1").arg(data.EndStr()), normalFont);
}
else
{
p = drawText(painter, p, QString(" %1").arg(tr("Running")), normalFont);
}

const QString errorCounter(QString::number(data.Errors()));
p.setX(width - fm.width("888") - margin);
painter->drawText(p, errorCounter);

QPixmap icon2(data.Errors() > 0 ? m_icon3 : m_icon2);
painter->drawPixmap(p.x() - icon2.width() - 3, topLeft.y() + margin, icon2);
}

}

bool ComboUpDownDelegate::eventFilter(QObject *object, QEvent *event) {
auto combo = static_cast<QComboBox*>(object);

if (combo != nullptr && object == this->parent() && event->type() == QEvent::Paint) {
QStylePainter painter(combo);

painter.setPen(combo->palette().color(QPalette::Text));

QStyleOptionComboBox opt;
opt.initFrom(combo);
opt.editable = combo->isEditable();
opt.frame = combo->hasFrame();
if (combo->hasFocus() && !opt.editable) {
opt.state |= QStyle::State_Selected;
}
opt.subControls = QStyle::SC_All;

if (m_title.isEmpty()) {
opt.currentText = combo->currentText();
} else {
opt.currentText = m_title.arg(combo->count());
}
painter.drawComplexControl(QStyle::CC_ComboBox, opt);
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);

if (combo->property(COMBO_TYPE) == COMBO_ICON_RICHTEXT_COUNTER) {
drawIconRichTextCounter(&painter, combo->currentData(SESSION_DATA_ROLE).value<CUDSession>(),
QPoint(0, 0), combo->currentIndex(), combo->width() - 16);
}

return true;
}
return QStyledItemDelegate::eventFilter(object, event);
}

void ComboUpDownDelegate::setTitle(const QString& title) {
m_title = title;
}

QString ComboUpDownDelegate::title() const {
return m_title;
}

Where I create the combo:

auto comboSesiones = new QComboBox();
comboSesiones->setProperty(ComboUpDownDelegate::COMBO_TYPE, ComboUpDownDelegate::COMBO_ICON_RICHTEXT_COUNTER);
comboSesiones->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::A djustToContents);
comboSesiones->setMinimumWidth(525);
auto delegate = new ComboUpDownDelegate(comboSesiones);
comboSesiones->setItemDelegate(delegate);
connect(comboSesiones, SIGNAL(currentIndexChanged(int)), SLOT(onSesionCurrentChanged(int)));
comboSesiones->setVisible(false);
comboSesiones->addItem("");
int index = comboSesiones->count() - 1;
comboSesiones->setItemData(index, QVariant(), ComboUpDownDelegate::SESSION_DATA_ROLE);

Thank you very much.

PinTxO
14th October 2015, 10:38
¿Any idea?:(