Update the combobox delegate in runtime while the popup is opened
Hi everyone.
I have a QStyleItemDelegate for my QCombobox where I show an icon with a text and two more icons.
The items are displayed well but there is an incorrect behaviour when the user has opened the popup of the combobox. The icons change in runtime and when the popup is opened by the user, in spite of doing a "combobox.update" the icons don't refresh. They only refresh when I close the popup and I open it again. A curious thing too happens when I move the mouse on a combobox item because that item refreshes, but only that one.
¿Any help? Thanks
Re: Update the combobox delegate in runtime while the popup is opened
Post the code of your delegate (or other relevant code) so we can have an idea how to help you.
Re: Update the combobox delegate in runtime while the popup is opened
Thanks for your interest. Here is my delegate:
Code:
ComboUpDownDelegate
::ComboUpDownDelegate(QObject* parent
): AuniaComboDelegate_Base
(parent
) { auto combobox = qobject_cast<QComboBox*>(parent);
initCombo(combobox);
// Icons
m_iconClock
= Customisation
::getImage("time",
QSize(16,
16),
QColor("#C8C8C8"));
m_iconWarningNoErrors
= Customisation
::getImage("warning",
QSize(16,
16),
QColor("#C8C8C8"));
...
...more icons
...
}
ComboUpDownDelegate::~ComboUpDownDelegate() {
}
void ComboUpDownDelegate
::initCombo(QComboBox* combo
) { if (combo != nullptr) {
combo->installEventFilter(this);
}
}
auto combo = static_cast<QComboBox*>(this->parent());
const auto text = index.data(Qt::DisplayRole).toString();
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());
}
QWidget* ComboUpDownDelegate
::createEditor(QWidget* parent,
const QStyleOptionViewItem
& option,
const QModelIndex& index) const {
return nullptr;
}
QComboBox* combo
= static_cast<QComboBox
*>
(this
->parent
());
// Basic style
QStyleOptionViewItemV4 modifiedOption(option);
modifiedOption.text.clear();
modifiedOption.
icon = QIcon();
const auto topLeft = option.rect.topLeft();
const int margin = 3;
painter
->setPen
(combo
->palette
().
color(QPalette::Text));
// Icon for the state of the device
const bool state1 = index.data(ICON1_ROLE).toBool();
QPixmap icon1
(state1 ? m_iconDeviceConnected
: m_iconDeviceDisconnected
);
painter->drawPixmap(margin, topLeft.y() + margin + 4, icon1);
// Text to show
QFont normalFont
(painter
->font
());
normalFont.setBold(false);
QFont boldFont
(normalFont
);
boldFont.setBold(true);
painter
->setPen
(QColor("#7C7C7C"));
QPoint p
(topLeft
+ QPoint(icon1.
width() + 2.5 * margin, fm.
height() + 6));
const QString deviceText
= index.
data(Qt
::DisplayRole).
toString();
const QString UTText
= " - " + index.
data(UT_ROLE
).
toString();
p = drawText(painter, p, deviceText, boldFont);
p.setX(p.x() + 2);
p = drawText(painter, p, UTText, normalFont);
// Icon for the state of the last execution
const int state3 = index.data(ICON3_ROLE).toInt();
switch (state3) {
case 1:
icon3 = m_iconExecutionNoErrors;
break;
case 2:
icon3 = m_iconExecutionErrors;
break;
case 3:
icon3 = m_iconRunning;
break;
default:
noIcon3 = m_iconExecutionNoErrors;
break;
}
int w;
if(!icon3.isNull())
{
w = option.rect.width() - icon3.width() - margin;
painter->drawPixmap(w, topLeft.y() + margin + 8, icon3);
}
else
{
w = option.rect.width() - noIcon3.width() - margin;
}
// Icon to filter the traces of the devices
const int state2 = index.data(ICON2_ROLE).toInt();
switch (state2) {
case 1:
icon2 = m_iconEye;
break;
case 2:
icon2 = m_iconStrikethroughEye;
break;
default:
noIcon2 = m_iconEye;
break;
}
if(!icon2.isNull())
{
w -= icon2.width();
w -= 8;
painter->drawPixmap(w, topLeft.y() + margin + 8, icon2);
}
}
bool ComboUpDownDelegate
::eventFilter(QObject *object,
QEvent *event
) { auto combo = qobject_cast<QComboBox*>(object);
if (combo
!= nullptr
&& object
== this
->parent
() && event
->type
() == QEvent::Paint) {
painter.
setPen(combo
->palette
().
color(QPalette::Text));
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
);
return true;
}
return QStyledItemDelegate::eventFilter(object, event);
}
void ComboUpDownDelegate::setTitle(const QString& title) {
m_title = title;
}
QString ComboUpDownDelegate
::title() const { return m_title;
}
And my code where I change the data of the combo:
Code:
comboDevices->setItemData(index, 0, ComboUpDownDelegate::ICON2_ROLE);
// Show the running icon
comboDevices->setItemData(index, 3, ComboUpDownDelegate::ICON3_ROLE);
comboDevices->update();
This code when the popup of the combobox is opened, the icons don't refresh
Re: Update the combobox delegate in runtime while the popup is opened
I solved the problem.
The thread that changed the value of each role was not the main thread. To solve it I've emitted a queued signal and without changing any line of code, the combo items refresh with the opened popup. I hope my solution will be useful for other developers.
Thanks