Questions regarding QAbstractTableModel and QDataWidgetMapper
-
I found that no matter I put toFirst(), toNext(), or toLast() the LineEdits being mapped by the mapper always contain the data from the first row of the table.
mapper->setOrientation(Qt::Horizontal); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); mapper->setModel(PhoneBookModel); connect( ui->tableView->selectionModel(),&QItemSelectionModel::currentRowChanged, mapper,&QDataWidgetMapper::setCurrentModelIndex); mapper->addMapping(ui->lineEdit,0); mapper->addMapping(ui->lineEdit_2,1); mapper->toLast();
What did I do wrong?
-
When are you adding data to your model ?
-
I added data to the model before the tableView set to that model:
aModel *PhoneBookModel = new aModel(this); PhoneBookModel->setContactsInfo("Thomas","123-456-7890"); PhoneBookModel->setContactsInfo("Richard","222-333-4444"); ui->tableView->setModel(PhoneBookModel); ui->tableView->horizontalHeader()->setVisible(true); ui->tableView->show();
Then I mapped the data of the model to lineEdits.
-
Did you already took a look at the Simple Widget Mapper Example ?
-
I did take a look at it before, but the example uses only 3 widgets for all rows of the table.
I wanted to make the number of widgets flexible:
As in the first card has different number of lineEdits compared to the second card when expanded.
I am thinking of using a different mapper here, set to the same model and map to different widgets:
PhoneBookModel->setContactsInfo("Thomas","123-456-7890"); PhoneBookModel->setContactsInfo("Richard","222-333-4444"); mapper->setModel(PhoneBookModel); connect( ui->tableView->selectionModel(),&QItemSelectionModel::currentRowChanged, mapper,&QDataWidgetMapper::setCurrentModelIndex); mapper->addMapping(ui->lineEdit,0); mapper->addMapping(ui->lineEdit_2,1); mapper->toFirst(); // another mapper QDataWidgetMapper *anotherMapper = new QDataWidgetMapper(this); anotherMapper->setModel(PhoneBookModel); connect( ui->tableView->selectionModel(),&QItemSelectionModel::currentRowChanged, anotherMapper,&QDataWidgetMapper::setCurrentModelIndex); // toLast() doesn't work as what I thought it would anotherMapper->toLast(); anotherMapper->addMapping(ui->lineEdit_3,0); anotherMapper->addMapping(ui->lineEdit_4,1);
The code above doesn't work as the toLast() doesn't work as what I thought it would; changing the row currently pointing to in a model.
-
How do you build these different widgets ?
-
should be something like:
#include <QLineEdit> #include <QStyledItemDelegate> #include <QFormLayout> #include <QPainter> #include <QAbstractItemModel> #include <QRegularExpressionValidator> class ContactEditor : public QWidget{ Q_OBJECT Q_DISABLE_COPY(ContactEditor) public: explicit ContactEditor(QWidget* parent = nullptr) :QWidget(parent) , m_nameEdit(new QLineEdit(this)) , m_phoneEdit(new QLineEdit(this)) { QFormLayout* mainLay = new QFormLayout(this); mainLay->addRow(tr("Name"),m_nameEdit); mainLay->addRow(tr("Phone"),m_phoneEdit); auto phoneValidator = new QRegularExpressionValidator(this); phoneValidator->setRegularExpression(QRegularExpression(QStringLiteral("[\\d-]*"))); m_phoneEdit->setValidator(phoneValidator); } QString name() const{return m_nameEdit->text();} void setName(const QString& val) {m_nameEdit->setText(val);} QString phone() const{return m_phoneEdit->text();} void setPhone(const QString& val) {m_phoneEdit->setText(val);} private: QLineEdit* m_nameEdit; QLineEdit* m_phoneEdit; }; template <class T> class WidgetDelegate : public QStyledItemDelegate{ #ifdef Q_COMPILER_STATIC_ASSERT static_assert(std::is_base_of<QWidget,T>::value,"Template argument must be a QWidget"); #endif Q_DISABLE_COPY(WidgetDelegate) public: explicit WidgetDelegate(QObject* parent = Q_NULLPTR) :QStyledItemDelegate(parent) , m_baseWid(new T) {} ~WidgetDelegate(){ delete m_baseWid; } void paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE{ setSubEditorData(m_baseWid,index); m_baseWid->resize(option.rect.size()); QPixmap pixmap(option.rect.size()); m_baseWid->render(&pixmap); painter->drawPixmap(option.rect,pixmap); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{ Q_UNUSED(option); setSubEditorData(m_baseWid,index); return m_baseWid->sizeHint(); } QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE Q_DECL_FINAL { Q_UNUSED(option); Q_UNUSED(index); T* editor = new T; editor->setParent(parent); return editor; } virtual void setSubEditorData(T* editor, const QModelIndex &index) const =0; void setEditorData(QWidget* editor, const QModelIndex &index) const Q_DECL_OVERRIDE Q_DECL_FINAL { T* subEdit = qobject_cast<T*>(editor); Q_ASSERT(subEdit); return setSubEditorData(subEdit,index); } private: T* m_baseWid; }; class ContactDelegate : public WidgetDelegate<ContactEditor>{ Q_DISABLE_COPY(ContactDelegate) public: explicit ContactDelegate(QObject* parent=Q_NULLPTR) :WidgetDelegate<ContactEditor>(parent) {} void setSubEditorData(ContactEditor* editor, const QModelIndex &index) const Q_DECL_OVERRIDE{ editor->setName( displayText(index.data(),editor->locale())); editor->setPhone(displayText(index.data(Qt::UserRole),editor->locale())); } };
and then you can use it in a delegate like:
int main(int argc, char **argv) { QApplication app(argc,argv); QListWidget wid; wid.setEditTriggers(QAbstractItemView::AllEditTriggers); wid.setItemDelegate(new ContactDelegate(&wid)); wid.model()->insertRows(0,2); wid.model()->setData(wid.model()->index(0,0),"Thomas"); wid.model()->setData(wid.model()->index(0,0),"123456789",Qt::UserRole); wid.model()->setData(wid.model()->index(1,0),"Richard"); wid.model()->setData(wid.model()->index(1,0),"987654321",Qt::UserRole); wid.show(); return app.exec(); }