PDA

View Full Version : Problems in understanding how to use a QComboBox in my QTableView derived class



franco.amato
19th November 2021, 00:58
Hi community,
in my code I have added a view derived from QTableView having 2 columns and x rows ( x is not fixed but grows ).
The first column contains text and there I show the content of the model that stores internally a string of strings.
The second columns have show a QComboBox where the user should be able to choose one of the combobox options (also a QString). I am using a class derived from QStyledItemDelegate for that purpose.
I have no problems with the first column, I can correctly add new rows with the right text.
My problem is with the column #2, I can show the combobox with the options but, after choosing one, if I click anywhere in the view, the combobox value clears.
So seems I am doing something wrong in storing and read the corect combobox value.

Here the code I used to create the item delegate

*.h


#ifndef SELECTEDLISTITEMDELEGATE_H
#define SELECTEDLISTITEMDELEGATE_H

#include <QStyledItemDelegate>

class SelectedListItemDelegate : public QStyledItemDelegate
{
Q_OBJECT

public:
SelectedListItemDelegate(QObject *parent = nullptr);
~SelectedListItemDelegate() override;

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
};

#endif

and the cpp


#include "SelectedListItemDelegate.h"
#include <QComboBox>
#include <QDebug>

SelectedListItemDelegate::SelectedListItemDelegate (QObject* parent)
: QStyledItemDelegate(parent)
{
}

SelectedListItemDelegate::~SelectedListItemDelegat e()
{
}

QWidget *SelectedListItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option)

QComboBox *comboBox = new QComboBox(parent);

// I considere 3 options just as an example
const int row = index.row();
comboBox->addItem(QString("Option %1").arg(row));
comboBox->addItem(QString("Option %1").arg(row));
comboBox->addItem(QString("Option %1").arg(row));

return comboBox;
}

// This routine does not set any value in the combobox
void SelectedListItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QString value = index.model()->data(index, Qt::EditRole).toString();
qDebug() << "Value:" << value; // Value is empty
QComboBox *comboBox = qobject_cast<QComboBox*>(editor);
comboBox->setCurrentIndex(comboBox->findText(value));
}

// Seems that the combobox value is not correctly written because is not kept in the cell. If I click outside its cleared
void SelectedListItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QComboBox *comboBox = qobject_cast<QComboBox *>(editor);
QString value = comboBox->currentText();
model->setData(index, value, Qt::EditRole);
}

Can I have a help in understanding what's I am doing wrong?
Thanx

d_stranz
19th November 2021, 15:25
Can I have a help in understanding what's I am doing wrong?

In your model's setData() method, are you issuing the signals to tell views that the data has changed? QAbstractItemModel::dataChanged(), QAbstractItemModel::layoutAboutToBeChanged(), QAbstractItemModel::layoutChanged() or the protected methods when rows / columns are added or removed?

If the model does not send out the signals to tell views that its content has changed, then the view does not know it has to update. And when editing is finished, the delegate is destroyed along with whatever it was showing on screen. So the view remains the same as it was before editing.

franco.amato
21st November 2021, 15:32
Thank you for the answer.
Can I have a piece of code to better understand?

d_stranz
22nd November 2021, 04:37
Can I have a piece of code to better understand?

It would be better if you posted the code you have in your model's setData() method. That's where whatever needs to be done to notify views of a change in the model has to occur.

franco.amato
23rd November 2021, 13:42
It would be better if you posted the code you have in your model's setData() method. That's where whatever needs to be done to notify views of a change in the model has to occur.

Below the code of setData()


bool SelectedListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == Qt::EditRole && index.isValid())
{
m_reports[index.row()].replace("actionName", value.toString());

emit dataChanged(index, index, {role});
return true;
}

return false;
}

And data()


QVariant SelectedListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
{
return QVariant();
}
if (index.row() >= m_reports.size() || index.row() < 0)
{
return QVariant();
}
if (role == Qt::DisplayRole)
{
const QMultiMap<QString, QString>& report = m_reports.at(index.row());

QString reportName = report.value("reportName");
QString actionName = report.value("actionName");

if (index.column() == 0)
{
return reportName;
}
else if (index.column() == 1)
{
return actionName;
}
}
else if (role == Qt::BackgroundRole)
{
if (index.column() == 1)
{
QString cellContent = index.data().toString();
if (cellContent.contains("Click here"))
{
return QVariant(QColor("#FF4500"));
}
else
return QVariant(QColor("#32CD32"));
}
}
else if (role == Qt::TextAlignmentRole && index.column() == 1)
{
return Qt::AlignHCenter;
}
else if (role == Qt::FontRole)
{
QFont font;
font.setFamily("Optima");
font.setPointSize(10);
return font;
}

return QVariant();
}

In the data() method I have a condition to specify the cells of column 1 background color but, the color does't not change until i click anywhere in the tableview.
How can I fix it?
Thank you

d_stranz
23rd November 2021, 17:02
emit dataChanged(index, index, {role});

I think your "role" here needs to be Qt::DisplayRole. EditRole is used only when editing, not when updating the view after editing.


In the data() method I have a condition to specify the cells of column 1 background color but, the color does't not change until i click anywhere in the tableview.
How can I fix it?

The Qt::BackgroundRole is used when drawing items that have the default delegate. Since you have a custom delegate, you may need to implement the QStyledItemDelegate::paint() method to draw the delegate with the correct background color. Note that if you do this, you also have to implement the sizeHint() method.