QItemDelegate with QComboBox and QSpinBox with QTableView control (how to pass signal)
-
@shylock said in QItemDelegate with QComboBox and QSpinBox with QTableView control (how to pass signal):
If you prefer I can attach a cut down version of a project.
That would be really useful
@VRonin
I wonder did anyone managed to figure out, above stated problem logic?
Although I have a crude solution for the same problem which works. But I am interested to have more efficient and less CPU intensive solution, I am sure there were many Qt experts exists on the Forum with huge points in their credit, surely may have to jog their Qt knowledge to an extra mile or on a treadmill? -
@VRonin
I wonder did anyone managed to figure out, above stated problem logic?
Although I have a crude solution for the same problem which works. But I am interested to have more efficient and less CPU intensive solution, I am sure there were many Qt experts exists on the Forum with huge points in their credit, surely may have to jog their Qt knowledge to an extra mile or on a treadmill? -
Unfortunately the posted code is not enough to test it.
A few notes/questions:
- What should
QStyledItemDelegate m_siDelegate;do? ProdIdDelegate::paintdoesn't do anything. is that what you want?ProdIdDelegate::sizeHintwhy do you reimplement it? just delete itui->mytableView->openPersistentEditorwhy do you use this if you are using a custom delegate?- Why do you call a query evey time to refresh the combo instead of just using a member
QSqlTableModel? - What should
ProdIdDelegate::m_proid,ProdIdDelegate::m_description,ProdIdDelegate::m_pricerepresent?
- What should
-
Unfortunately the posted code is not enough to test it.
A few notes/questions:
- What should
QStyledItemDelegate m_siDelegate;do? ProdIdDelegate::paintdoesn't do anything. is that what you want?ProdIdDelegate::sizeHintwhy do you reimplement it? just delete itui->mytableView->openPersistentEditorwhy do you use this if you are using a custom delegate?- Why do you call a query evey time to refresh the combo instead of just using a member
QSqlTableModel? - What should
ProdIdDelegate::m_proid,ProdIdDelegate::m_description,ProdIdDelegate::m_pricerepresent?
@VRonin
1/ The vars editor,model,index simply to reuse them instead of having a warning messages.
2/ ProdIdDelegate::paint does not do anything due it does not have a handle of myTableView control which
resides in dialog class, hence it cant precisely paint the column 2 and 3
3/ Ignore::sizeHint function it is there and according to QStyledItemDelegate help note this function can be
overwritten.
4/ First time SQL Query called to fill or populate the QComboBox for user's selection, after selection prodId
The second time SQL Query called find description and price. Although This can be amalgamated in a single
call. But I thought since I have a Signal to process I can use this facility to re-scan the table again with
prodId pick the Description, and Price; this info extracted from a SQLITE3 table and displayed in
Dialog::myTableView table column 1 and 3 respectively. m_prodId, m_description, are string variable and
m_price is double.
5/ If you see the attached png file will explain a bit more in details. - What should
-
Unfortunately the posted code is not enough to test it.
A few notes/questions:
- What should
QStyledItemDelegate m_siDelegate;do? ProdIdDelegate::paintdoesn't do anything. is that what you want?ProdIdDelegate::sizeHintwhy do you reimplement it? just delete itui->mytableView->openPersistentEditorwhy do you use this if you are using a custom delegate?- Why do you call a query evey time to refresh the combo instead of just using a member
QSqlTableModel? - What should
ProdIdDelegate::m_proid,ProdIdDelegate::m_description,ProdIdDelegate::m_pricerepresent?
@VRonin
The posted code file Dialog.cpp; from constructor, if you remove two variables, whose code is not posted
m_qtyspinDelegate= new QtySpin(this);
m_vatDelegate = new VATDelegate(this);This program a compile successfully and run with single QComboBox Delegate.
- What should
-
I'm missing the ui file.
Btw it looks like you are trying to use the delegate to do something that should not do. a delegate should paint and handle the edit of 1 and only 1 QModelIndex.
Remove
ui->mytableView->openPersistentEditoras it just destroys performance.this is a possible implementation of a combo box delegate I had around:
header
#ifndef COMBOBOXDELEGATE_H #define COMBOBOXDELEGATE_H #include <QStyledItemDelegate> #include <QString> class QComboBox; class QStandardItemModel; class QSortFilterProxyModel; class ComboBoxDelegate : public QStyledItemDelegate { Q_OBJECT Q_DISABLE_COPY(ComboBoxDelegate) public: ComboBoxDelegate(QObject *parent = Q_NULLPTR); virtual ~ComboBoxDelegate() = default; virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void clear(); virtual void addItem(const QString& txt, const QVariant& val); virtual void addItem(const QString& txt); virtual QString textForData(const QVariant& val); virtual void setItemData(int index, const QVariant& data, int role = Qt::UserRole); virtual QVariant itemData(int index, int role = Qt::UserRole); virtual void removeItem(int index); virtual int findText(const QString & text) const; virtual int findData(const QVariant & data, int role = Qt::UserRole) const; virtual QAbstractItemModel* model() const; bool alwaysPaintCombo() const; void setAlwaysPaintCombo(bool val); protected: QStandardItemModel* m_comboModel; QSortFilterProxyModel* m_comboProxy; bool m_alwaysPaintCombo; }; #endif // COMBOBOXDELEGATE_HSource
#include "ComboBoxDelegate.h" #include <QComboBox> #include <QStandardItemModel> #include <QApplication> #include <QSortFilterProxyModel> #include <QStyleOptionComboBox> ComboBoxDelegate::ComboBoxDelegate(QObject *parent) : QStyledItemDelegate(parent) , m_alwaysPaintCombo(false) { m_comboModel = new QStandardItemModel(this); m_comboModel->insertColumn(0); m_comboProxy = new QSortFilterProxyModel(this); m_comboProxy->setSourceModel(m_comboModel); } void ComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!m_alwaysPaintCombo) return ComboBoxDelegate::paint(painter, option, index); const QWidget* const widget = option.widget; QStyle* const style = widget ? widget->style() : QApplication::style(); QStyleOptionComboBox cbOption; cbOption.rect = option.rect; cbOption.direction = option.direction; cbOption.currentIcon = index.data(Qt::DecorationRole).value<QIcon>(); cbOption.currentText = index.data(Qt::DisplayRole).toString(); cbOption.fontMetrics = option.fontMetrics; const int iconWidth = style->pixelMetric(QStyle::PM_SmallIconSize, Q_NULLPTR, widget); cbOption.iconSize = QSize(iconWidth, iconWidth); cbOption.palette = option.palette; cbOption.state = option.state; cbOption.styleObject = option.styleObject; style->drawComplexControl(QStyle::CC_ComboBox, &cbOption, painter, widget); style->drawControl(QStyle::CE_ComboBoxLabel, &cbOption, painter, widget); } QWidget* ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { QComboBox* result = new QComboBox(parent); m_comboProxy->sort(0); result->setModel(m_comboProxy); return result; } void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if (index.model()->data(index, Qt::EditRole).isNull()) qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1); else qobject_cast<QComboBox*>(editor)->setCurrentText(index.model()->data(index, Qt::EditRole).toString()); } void ComboBoxDelegate::clear() { m_comboModel->removeRows(0,m_comboModel->rowCount()); } void ComboBoxDelegate::addItem(const QString& txt, const QVariant& val) { const int newRow = m_comboModel->rowCount(); m_comboModel->insertRow(newRow); m_comboModel->setData(m_comboModel->index(newRow, 0), txt); m_comboModel->setData(m_comboModel->index(newRow, 0), val, Qt::UserRole); } void ComboBoxDelegate::addItem(const QString& txt) { addItem(txt, QVariant()); } QString ComboBoxDelegate::textForData(const QVariant& val) { for (int i = 0; i < m_comboModel->rowCount();++i){ if (m_comboModel->index(i, 0).data(Qt::UserRole) == val) return m_comboModel->index(i, 0).data().toString(); } return QString(); } void ComboBoxDelegate::setItemData(int index, const QVariant& data, int role) { if (index < 0 || index >= m_comboProxy->rowCount()) return; m_comboModel->setData(m_comboProxy->mapToSource(m_comboProxy->index(index, 0)), data, role); } QVariant ComboBoxDelegate::itemData(int index, int role) { if (index < 0 || index >= m_comboProxy->rowCount()) return QVariant(); return m_comboProxy->index(index, 0).data(role); } void ComboBoxDelegate::removeItem(int index) { if (index < 0 || index >= m_comboProxy->rowCount()) return; m_comboModel->removeRow(m_comboProxy->mapToSource(m_comboProxy->index(index,0)).row()); } int ComboBoxDelegate::findText(const QString & text) const { for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (m_comboProxy->index(i, 0).data().toString().compare(text, Qt::CaseInsensitive) == 0) return i; } return -1; } int ComboBoxDelegate::findData(const QVariant & data, int role) const { for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (m_comboProxy->index(i, 0).data(role) == data) return i; } return -1; } QAbstractItemModel* ComboBoxDelegate::model() const { return m_comboModel; } bool ComboBoxDelegate::alwaysPaintCombo() const { return m_alwaysPaintCombo; } void ComboBoxDelegate::setAlwaysPaintCombo(bool val) { m_alwaysPaintCombo = val; } void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { auto combo = qobject_cast<QComboBox*>(editor); if (combo->currentIndex() < 0) { model->setData(index, QVariant(), Qt::EditRole); model->setData(index, QVariant(), Qt::UserRole); } else { model->setData(index, combo->currentText(), Qt::EditRole); model->setData(index, combo->currentData(), Qt::UserRole); } } void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const { editor->setGeometry(option.rect); } QSize ComboBoxDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const { int MaxWid = 0; for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (option.fontMetrics.width(m_comboProxy->index(i, 0).data().toString())>MaxWid) MaxWid = option.fontMetrics.width(m_comboProxy->index(i, 0).data().toString()); } return qApp->style()->sizeFromContents( QStyle::CT_ComboBox, &option, QSize(MaxWid, option.fontMetrics.height()) ); } -
I'm missing the ui file.
Btw it looks like you are trying to use the delegate to do something that should not do. a delegate should paint and handle the edit of 1 and only 1 QModelIndex.
Remove
ui->mytableView->openPersistentEditoras it just destroys performance.this is a possible implementation of a combo box delegate I had around:
header
#ifndef COMBOBOXDELEGATE_H #define COMBOBOXDELEGATE_H #include <QStyledItemDelegate> #include <QString> class QComboBox; class QStandardItemModel; class QSortFilterProxyModel; class ComboBoxDelegate : public QStyledItemDelegate { Q_OBJECT Q_DISABLE_COPY(ComboBoxDelegate) public: ComboBoxDelegate(QObject *parent = Q_NULLPTR); virtual ~ComboBoxDelegate() = default; virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void clear(); virtual void addItem(const QString& txt, const QVariant& val); virtual void addItem(const QString& txt); virtual QString textForData(const QVariant& val); virtual void setItemData(int index, const QVariant& data, int role = Qt::UserRole); virtual QVariant itemData(int index, int role = Qt::UserRole); virtual void removeItem(int index); virtual int findText(const QString & text) const; virtual int findData(const QVariant & data, int role = Qt::UserRole) const; virtual QAbstractItemModel* model() const; bool alwaysPaintCombo() const; void setAlwaysPaintCombo(bool val); protected: QStandardItemModel* m_comboModel; QSortFilterProxyModel* m_comboProxy; bool m_alwaysPaintCombo; }; #endif // COMBOBOXDELEGATE_HSource
#include "ComboBoxDelegate.h" #include <QComboBox> #include <QStandardItemModel> #include <QApplication> #include <QSortFilterProxyModel> #include <QStyleOptionComboBox> ComboBoxDelegate::ComboBoxDelegate(QObject *parent) : QStyledItemDelegate(parent) , m_alwaysPaintCombo(false) { m_comboModel = new QStandardItemModel(this); m_comboModel->insertColumn(0); m_comboProxy = new QSortFilterProxyModel(this); m_comboProxy->setSourceModel(m_comboModel); } void ComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!m_alwaysPaintCombo) return ComboBoxDelegate::paint(painter, option, index); const QWidget* const widget = option.widget; QStyle* const style = widget ? widget->style() : QApplication::style(); QStyleOptionComboBox cbOption; cbOption.rect = option.rect; cbOption.direction = option.direction; cbOption.currentIcon = index.data(Qt::DecorationRole).value<QIcon>(); cbOption.currentText = index.data(Qt::DisplayRole).toString(); cbOption.fontMetrics = option.fontMetrics; const int iconWidth = style->pixelMetric(QStyle::PM_SmallIconSize, Q_NULLPTR, widget); cbOption.iconSize = QSize(iconWidth, iconWidth); cbOption.palette = option.palette; cbOption.state = option.state; cbOption.styleObject = option.styleObject; style->drawComplexControl(QStyle::CC_ComboBox, &cbOption, painter, widget); style->drawControl(QStyle::CE_ComboBoxLabel, &cbOption, painter, widget); } QWidget* ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { QComboBox* result = new QComboBox(parent); m_comboProxy->sort(0); result->setModel(m_comboProxy); return result; } void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if (index.model()->data(index, Qt::EditRole).isNull()) qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1); else qobject_cast<QComboBox*>(editor)->setCurrentText(index.model()->data(index, Qt::EditRole).toString()); } void ComboBoxDelegate::clear() { m_comboModel->removeRows(0,m_comboModel->rowCount()); } void ComboBoxDelegate::addItem(const QString& txt, const QVariant& val) { const int newRow = m_comboModel->rowCount(); m_comboModel->insertRow(newRow); m_comboModel->setData(m_comboModel->index(newRow, 0), txt); m_comboModel->setData(m_comboModel->index(newRow, 0), val, Qt::UserRole); } void ComboBoxDelegate::addItem(const QString& txt) { addItem(txt, QVariant()); } QString ComboBoxDelegate::textForData(const QVariant& val) { for (int i = 0; i < m_comboModel->rowCount();++i){ if (m_comboModel->index(i, 0).data(Qt::UserRole) == val) return m_comboModel->index(i, 0).data().toString(); } return QString(); } void ComboBoxDelegate::setItemData(int index, const QVariant& data, int role) { if (index < 0 || index >= m_comboProxy->rowCount()) return; m_comboModel->setData(m_comboProxy->mapToSource(m_comboProxy->index(index, 0)), data, role); } QVariant ComboBoxDelegate::itemData(int index, int role) { if (index < 0 || index >= m_comboProxy->rowCount()) return QVariant(); return m_comboProxy->index(index, 0).data(role); } void ComboBoxDelegate::removeItem(int index) { if (index < 0 || index >= m_comboProxy->rowCount()) return; m_comboModel->removeRow(m_comboProxy->mapToSource(m_comboProxy->index(index,0)).row()); } int ComboBoxDelegate::findText(const QString & text) const { for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (m_comboProxy->index(i, 0).data().toString().compare(text, Qt::CaseInsensitive) == 0) return i; } return -1; } int ComboBoxDelegate::findData(const QVariant & data, int role) const { for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (m_comboProxy->index(i, 0).data(role) == data) return i; } return -1; } QAbstractItemModel* ComboBoxDelegate::model() const { return m_comboModel; } bool ComboBoxDelegate::alwaysPaintCombo() const { return m_alwaysPaintCombo; } void ComboBoxDelegate::setAlwaysPaintCombo(bool val) { m_alwaysPaintCombo = val; } void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { auto combo = qobject_cast<QComboBox*>(editor); if (combo->currentIndex() < 0) { model->setData(index, QVariant(), Qt::EditRole); model->setData(index, QVariant(), Qt::UserRole); } else { model->setData(index, combo->currentText(), Qt::EditRole); model->setData(index, combo->currentData(), Qt::UserRole); } } void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const { editor->setGeometry(option.rect); } QSize ComboBoxDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const { int MaxWid = 0; for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (option.fontMetrics.width(m_comboProxy->index(i, 0).data().toString())>MaxWid) MaxWid = option.fontMetrics.width(m_comboProxy->index(i, 0).data().toString()); } return qApp->style()->sizeFromContents( QStyle::CT_ComboBox, &option, QSize(MaxWid, option.fontMetrics.height()) ); }@VRonin
Thank you, Ronin,
Although I am going through the codes, I have attached my bog standard cut down version of the program, it is not an efficient way to complete and I am still looking a more tangible solution to complete the project.
Your provided class seems to more help a QComboBox and its various virtual functions.
AS you mentioned in the last post I am trying to do away different nature of job from QStyledItemDelegate class; perhaps you are right and in my judgment, if QStyledItemDelegate class provide a facility such as combo box, spin box, progress bar sliders, and other controls can be embedded into QTableView, QListView, QTreeView then their functionality can be must be more transparent to an extend functionality suited to a developer. As in this case nothing new as you can depict from the png image.
I am still grappling with real-time synchronization with two combo box and qty spin box selection, with their changes while displaying info on the QTableView Grid in a formatted manner.
-
I'm missing the ui file.
Btw it looks like you are trying to use the delegate to do something that should not do. a delegate should paint and handle the edit of 1 and only 1 QModelIndex.
Remove
ui->mytableView->openPersistentEditoras it just destroys performance.this is a possible implementation of a combo box delegate I had around:
header
#ifndef COMBOBOXDELEGATE_H #define COMBOBOXDELEGATE_H #include <QStyledItemDelegate> #include <QString> class QComboBox; class QStandardItemModel; class QSortFilterProxyModel; class ComboBoxDelegate : public QStyledItemDelegate { Q_OBJECT Q_DISABLE_COPY(ComboBoxDelegate) public: ComboBoxDelegate(QObject *parent = Q_NULLPTR); virtual ~ComboBoxDelegate() = default; virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void clear(); virtual void addItem(const QString& txt, const QVariant& val); virtual void addItem(const QString& txt); virtual QString textForData(const QVariant& val); virtual void setItemData(int index, const QVariant& data, int role = Qt::UserRole); virtual QVariant itemData(int index, int role = Qt::UserRole); virtual void removeItem(int index); virtual int findText(const QString & text) const; virtual int findData(const QVariant & data, int role = Qt::UserRole) const; virtual QAbstractItemModel* model() const; bool alwaysPaintCombo() const; void setAlwaysPaintCombo(bool val); protected: QStandardItemModel* m_comboModel; QSortFilterProxyModel* m_comboProxy; bool m_alwaysPaintCombo; }; #endif // COMBOBOXDELEGATE_HSource
#include "ComboBoxDelegate.h" #include <QComboBox> #include <QStandardItemModel> #include <QApplication> #include <QSortFilterProxyModel> #include <QStyleOptionComboBox> ComboBoxDelegate::ComboBoxDelegate(QObject *parent) : QStyledItemDelegate(parent) , m_alwaysPaintCombo(false) { m_comboModel = new QStandardItemModel(this); m_comboModel->insertColumn(0); m_comboProxy = new QSortFilterProxyModel(this); m_comboProxy->setSourceModel(m_comboModel); } void ComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!m_alwaysPaintCombo) return ComboBoxDelegate::paint(painter, option, index); const QWidget* const widget = option.widget; QStyle* const style = widget ? widget->style() : QApplication::style(); QStyleOptionComboBox cbOption; cbOption.rect = option.rect; cbOption.direction = option.direction; cbOption.currentIcon = index.data(Qt::DecorationRole).value<QIcon>(); cbOption.currentText = index.data(Qt::DisplayRole).toString(); cbOption.fontMetrics = option.fontMetrics; const int iconWidth = style->pixelMetric(QStyle::PM_SmallIconSize, Q_NULLPTR, widget); cbOption.iconSize = QSize(iconWidth, iconWidth); cbOption.palette = option.palette; cbOption.state = option.state; cbOption.styleObject = option.styleObject; style->drawComplexControl(QStyle::CC_ComboBox, &cbOption, painter, widget); style->drawControl(QStyle::CE_ComboBoxLabel, &cbOption, painter, widget); } QWidget* ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { QComboBox* result = new QComboBox(parent); m_comboProxy->sort(0); result->setModel(m_comboProxy); return result; } void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if (index.model()->data(index, Qt::EditRole).isNull()) qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1); else qobject_cast<QComboBox*>(editor)->setCurrentText(index.model()->data(index, Qt::EditRole).toString()); } void ComboBoxDelegate::clear() { m_comboModel->removeRows(0,m_comboModel->rowCount()); } void ComboBoxDelegate::addItem(const QString& txt, const QVariant& val) { const int newRow = m_comboModel->rowCount(); m_comboModel->insertRow(newRow); m_comboModel->setData(m_comboModel->index(newRow, 0), txt); m_comboModel->setData(m_comboModel->index(newRow, 0), val, Qt::UserRole); } void ComboBoxDelegate::addItem(const QString& txt) { addItem(txt, QVariant()); } QString ComboBoxDelegate::textForData(const QVariant& val) { for (int i = 0; i < m_comboModel->rowCount();++i){ if (m_comboModel->index(i, 0).data(Qt::UserRole) == val) return m_comboModel->index(i, 0).data().toString(); } return QString(); } void ComboBoxDelegate::setItemData(int index, const QVariant& data, int role) { if (index < 0 || index >= m_comboProxy->rowCount()) return; m_comboModel->setData(m_comboProxy->mapToSource(m_comboProxy->index(index, 0)), data, role); } QVariant ComboBoxDelegate::itemData(int index, int role) { if (index < 0 || index >= m_comboProxy->rowCount()) return QVariant(); return m_comboProxy->index(index, 0).data(role); } void ComboBoxDelegate::removeItem(int index) { if (index < 0 || index >= m_comboProxy->rowCount()) return; m_comboModel->removeRow(m_comboProxy->mapToSource(m_comboProxy->index(index,0)).row()); } int ComboBoxDelegate::findText(const QString & text) const { for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (m_comboProxy->index(i, 0).data().toString().compare(text, Qt::CaseInsensitive) == 0) return i; } return -1; } int ComboBoxDelegate::findData(const QVariant & data, int role) const { for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (m_comboProxy->index(i, 0).data(role) == data) return i; } return -1; } QAbstractItemModel* ComboBoxDelegate::model() const { return m_comboModel; } bool ComboBoxDelegate::alwaysPaintCombo() const { return m_alwaysPaintCombo; } void ComboBoxDelegate::setAlwaysPaintCombo(bool val) { m_alwaysPaintCombo = val; } void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { auto combo = qobject_cast<QComboBox*>(editor); if (combo->currentIndex() < 0) { model->setData(index, QVariant(), Qt::EditRole); model->setData(index, QVariant(), Qt::UserRole); } else { model->setData(index, combo->currentText(), Qt::EditRole); model->setData(index, combo->currentData(), Qt::UserRole); } } void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const { editor->setGeometry(option.rect); } QSize ComboBoxDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const { int MaxWid = 0; for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (option.fontMetrics.width(m_comboProxy->index(i, 0).data().toString())>MaxWid) MaxWid = option.fontMetrics.width(m_comboProxy->index(i, 0).data().toString()); } return qApp->style()->sizeFromContents( QStyle::CT_ComboBox, &option, QSize(MaxWid, option.fontMetrics.height()) ); }@VRonin
I am afraid your provided class logic simply does not work as it cannot be instantiated, the function
paint is persistent in the paint state for QVariants; even the list become exhausted, it gave me far more aggro to embed within QTableView.
A basically I am still at Square One! The requirements (ie problem) remained stirring at me more vehemently than ever, I bet I have to go deep undercover in Qt's systems source code to do a bit of hacking. -
I'm missing the ui file.
Btw it looks like you are trying to use the delegate to do something that should not do. a delegate should paint and handle the edit of 1 and only 1 QModelIndex.
Remove
ui->mytableView->openPersistentEditoras it just destroys performance.this is a possible implementation of a combo box delegate I had around:
header
#ifndef COMBOBOXDELEGATE_H #define COMBOBOXDELEGATE_H #include <QStyledItemDelegate> #include <QString> class QComboBox; class QStandardItemModel; class QSortFilterProxyModel; class ComboBoxDelegate : public QStyledItemDelegate { Q_OBJECT Q_DISABLE_COPY(ComboBoxDelegate) public: ComboBoxDelegate(QObject *parent = Q_NULLPTR); virtual ~ComboBoxDelegate() = default; virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; virtual void clear(); virtual void addItem(const QString& txt, const QVariant& val); virtual void addItem(const QString& txt); virtual QString textForData(const QVariant& val); virtual void setItemData(int index, const QVariant& data, int role = Qt::UserRole); virtual QVariant itemData(int index, int role = Qt::UserRole); virtual void removeItem(int index); virtual int findText(const QString & text) const; virtual int findData(const QVariant & data, int role = Qt::UserRole) const; virtual QAbstractItemModel* model() const; bool alwaysPaintCombo() const; void setAlwaysPaintCombo(bool val); protected: QStandardItemModel* m_comboModel; QSortFilterProxyModel* m_comboProxy; bool m_alwaysPaintCombo; }; #endif // COMBOBOXDELEGATE_HSource
#include "ComboBoxDelegate.h" #include <QComboBox> #include <QStandardItemModel> #include <QApplication> #include <QSortFilterProxyModel> #include <QStyleOptionComboBox> ComboBoxDelegate::ComboBoxDelegate(QObject *parent) : QStyledItemDelegate(parent) , m_alwaysPaintCombo(false) { m_comboModel = new QStandardItemModel(this); m_comboModel->insertColumn(0); m_comboProxy = new QSortFilterProxyModel(this); m_comboProxy->setSourceModel(m_comboModel); } void ComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!m_alwaysPaintCombo) return ComboBoxDelegate::paint(painter, option, index); const QWidget* const widget = option.widget; QStyle* const style = widget ? widget->style() : QApplication::style(); QStyleOptionComboBox cbOption; cbOption.rect = option.rect; cbOption.direction = option.direction; cbOption.currentIcon = index.data(Qt::DecorationRole).value<QIcon>(); cbOption.currentText = index.data(Qt::DisplayRole).toString(); cbOption.fontMetrics = option.fontMetrics; const int iconWidth = style->pixelMetric(QStyle::PM_SmallIconSize, Q_NULLPTR, widget); cbOption.iconSize = QSize(iconWidth, iconWidth); cbOption.palette = option.palette; cbOption.state = option.state; cbOption.styleObject = option.styleObject; style->drawComplexControl(QStyle::CC_ComboBox, &cbOption, painter, widget); style->drawControl(QStyle::CE_ComboBoxLabel, &cbOption, painter, widget); } QWidget* ComboBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { QComboBox* result = new QComboBox(parent); m_comboProxy->sort(0); result->setModel(m_comboProxy); return result; } void ComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if (index.model()->data(index, Qt::EditRole).isNull()) qobject_cast<QComboBox*>(editor)->setCurrentIndex(-1); else qobject_cast<QComboBox*>(editor)->setCurrentText(index.model()->data(index, Qt::EditRole).toString()); } void ComboBoxDelegate::clear() { m_comboModel->removeRows(0,m_comboModel->rowCount()); } void ComboBoxDelegate::addItem(const QString& txt, const QVariant& val) { const int newRow = m_comboModel->rowCount(); m_comboModel->insertRow(newRow); m_comboModel->setData(m_comboModel->index(newRow, 0), txt); m_comboModel->setData(m_comboModel->index(newRow, 0), val, Qt::UserRole); } void ComboBoxDelegate::addItem(const QString& txt) { addItem(txt, QVariant()); } QString ComboBoxDelegate::textForData(const QVariant& val) { for (int i = 0; i < m_comboModel->rowCount();++i){ if (m_comboModel->index(i, 0).data(Qt::UserRole) == val) return m_comboModel->index(i, 0).data().toString(); } return QString(); } void ComboBoxDelegate::setItemData(int index, const QVariant& data, int role) { if (index < 0 || index >= m_comboProxy->rowCount()) return; m_comboModel->setData(m_comboProxy->mapToSource(m_comboProxy->index(index, 0)), data, role); } QVariant ComboBoxDelegate::itemData(int index, int role) { if (index < 0 || index >= m_comboProxy->rowCount()) return QVariant(); return m_comboProxy->index(index, 0).data(role); } void ComboBoxDelegate::removeItem(int index) { if (index < 0 || index >= m_comboProxy->rowCount()) return; m_comboModel->removeRow(m_comboProxy->mapToSource(m_comboProxy->index(index,0)).row()); } int ComboBoxDelegate::findText(const QString & text) const { for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (m_comboProxy->index(i, 0).data().toString().compare(text, Qt::CaseInsensitive) == 0) return i; } return -1; } int ComboBoxDelegate::findData(const QVariant & data, int role) const { for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (m_comboProxy->index(i, 0).data(role) == data) return i; } return -1; } QAbstractItemModel* ComboBoxDelegate::model() const { return m_comboModel; } bool ComboBoxDelegate::alwaysPaintCombo() const { return m_alwaysPaintCombo; } void ComboBoxDelegate::setAlwaysPaintCombo(bool val) { m_alwaysPaintCombo = val; } void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { auto combo = qobject_cast<QComboBox*>(editor); if (combo->currentIndex() < 0) { model->setData(index, QVariant(), Qt::EditRole); model->setData(index, QVariant(), Qt::UserRole); } else { model->setData(index, combo->currentText(), Qt::EditRole); model->setData(index, combo->currentData(), Qt::UserRole); } } void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const { editor->setGeometry(option.rect); } QSize ComboBoxDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const { int MaxWid = 0; for (int i = 0; i < m_comboProxy->rowCount(); ++i) { if (option.fontMetrics.width(m_comboProxy->index(i, 0).data().toString())>MaxWid) MaxWid = option.fontMetrics.width(m_comboProxy->index(i, 0).data().toString()); } return qApp->style()->sizeFromContents( QStyle::CT_ComboBox, &option, QSize(MaxWid, option.fontMetrics.height()) ); }