Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to insert/remove row into QTableView?



  • Hi, guys!
    I am using a QTableView to display some QWidgets for input. The first column is a QCheckBox, and the second to the fouth are all QComboBox.
    To make it, I use a class derived from QAbstractTableModel and a class derived from QStyledItemDelegate.
    The code of QAbstractTableModel is as below:

    class FormulaListModel : public QAbstractTableModel
    {
    	typedef struct
    	{
    		int op1;
    		int op2;
    		int op;
    		bool isEnable;
    	}FORMULA, *PFORMULA;
    	Q_OBJECT
    
    public:
    	FormulaListModel(QObject *parent);
    	~FormulaListModel();
    
    	/*Implement the necessary virtual function of QAbstractListModel*/
    	int rowCount(const QModelIndex & parent = QModelIndex()) const;
    	int columnCount(const QModelIndex & parent = QModelIndex()) const;
    	QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
    	bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
    
    	void AddDevName(QString name);//device names
    	void AddOperator(QString name);//operators
    	void AddFormula(int op1, int op2, int op, bool isEnable);//add formula
    private:
    	QVector<PFORMULA> m_lsFormula;
    	QStringList m_lsDevNames;
    	QStringList m_lsOperators;
    };
    FormulaListModel::FormulaListModel(QObject *parent)
    	: QAbstractTableModel(parent)
    {
    }
    
    FormulaListModel::~FormulaListModel()
    {
    	foreach(PFORMULA f, m_lsFormula)
    	{
    		if (f)
    		{
    			delete f;
    		}
    	}
    	m_lsFormula.clear();
    	m_lsDevNames.clear();
    	m_lsOperators.clear();
    }
    int FormulaListModel::rowCount(const QModelIndex & parent) const
    {
    	return m_lsFormula.count();
    }
    int FormulaListModel::columnCount(const QModelIndex & parent) const
    {
    	return 4;
    }
    QVariant FormulaListModel::data(const QModelIndex & index, int role) const
    {
    	switch(role)
    	{
    	case Qt::EditRole:
    		{
    			int r = index.row();
    			int c = index.column();
    			PFORMULA pf = m_lsFormula[r];
    			switch(c)
    			{
    			case 0:
    				return pf->isEnable;
    			case 1:
    				return m_lsDevNames[pf->op1];
    			case 2:
    				return m_lsOperators[pf->op];
    			case 3:
    				return m_lsDevNames[pf->op2];
    			}
    		}
    	case Qt::DisplayRole:
    		{
    			int c = index.column();
    
    			switch(c)
    			{
    			case 0:
    				return "Use";
    			case 1:
    			case 3:
    				return m_lsDevNames;
    			case 2:
    				return m_lsOperators;
    			}
    		}
    	case Qt::DecorationRole:
    		{
    			QColor clr(Qt::transparent);
    			return clr;
    		}
    	case Qt::SizeHintRole:
    		return QSize(130, 16);
    	case Qt::FontRole:
    		{
    			QFont font;
    			font.setBold(true);
    			return font;
    		}
    	case Qt::BackgroundRole:
    		{
    			QBrush brush(Qt::transparent);
    			return brush;
    		}
    	case Qt::TextAlignmentRole:
    		{
    			return Qt::AlignHCenter;
    		}
    	case Qt::CheckStateRole:
    		{
    			return Qt::Checked;
    		}
    	case Qt::TextColorRole:
    		{
    			QColor clr(Qt::black);
    			return clr;
    		}
    	case Qt::ToolTipRole:
    		{
    			return "Formula";
    		}
    	default:
    		return QVariant();
    	}
    }
    bool FormulaListModel::setData(const QModelIndex & index, const QVariant & value, int role)
    {
    	QModelIndex tl, rb;
    
    	tl = createIndex(0, 0);
    	rb = createIndex(m_lsFormula.count(), 3);
    	emit dataChanged(tl, rb);
    	return true;
    }
    
    void FormulaListModel::AddDevName(QString name)
    {
    	m_lsDevNames << name;
    }
    
    void FormulaListModel::AddOperator(QString name)
    {
    	m_lsOperators << name;
    }
    
    void FormulaListModel::AddFormula(int op1, int op2, int op, bool isEnable)
    {
    	beginResetModel();
    	PFORMULA pf = new FORMULA;
    	pf->op = op;
    	pf->op1 = op1;
    	pf->op2 = op2;
    	pf->isEnable = isEnable;
    	m_lsFormula << pf;
    	endResetModel();
    }
    

    Code of QStyledItemDelegate is as below:

    class CheckBoxDelegate : public QStyledItemDelegate
    {
    	Q_OBJECT
    
    public:
    	CheckBoxDelegate(QObject *parent);
    	~CheckBoxDelegate();
    
    	QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, 
    		const QModelIndex & index)const;
    	void setEditorData(QWidget * editor, const QModelIndex & index) const;
    	void updateEditorGeometry(QWidget *editor,
                                          const QStyleOptionViewItem &option,
                                          const QModelIndex &index) const;
    	void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
    	void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
    protected:
    	bool eventFilter ( QObject * editor, QEvent * event );
    private:
    	
    };
    CheckBoxDelegate::CheckBoxDelegate(QObject *parent)
    	: QStyledItemDelegate(parent)
    {
    
    }
    
    CheckBoxDelegate::~CheckBoxDelegate()
    {
    
    }
    QWidget * CheckBoxDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, 
    	const QModelIndex & index)const
    {
    	QVariant value = index.model()->data(index, Qt::DisplayRole);
    
    	if (index.column() == 0)
    	{
    		QCheckBox * pBox = new QCheckBox(parent);
    		pBox->setText(value.toString());
    		return pBox;
    	}
    	else
    	{
    		QComboBox * pBox = new QComboBox(parent);
    		pBox->addItems(value.toStringList());
    		return pBox;
    	}
    }
    void CheckBoxDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
    {
    	QVariant value = index.model()->data(index, Qt::EditRole);
    
    	if (index.column() == 0)
    	{
    		bool checked = value.toBool();
    
    		QCheckBox * pBox = static_cast<QCheckBox *>(editor);
    		if (pBox)
    		{
    			pBox->setChecked(checked);
    		}
    	}
    	else
    	{
    		QString str = index.model()->data(index, Qt::EditRole).toString();
    		//qDebug() << index << str;
    
    		QComboBox * pBox = static_cast<QComboBox *>(editor);
    		if (pBox)
    		{
    			pBox->setCurrentIndex(pBox->findText(str));
    		}
    	}
    }
    void CheckBoxDelegate::updateEditorGeometry(QWidget *editor,
                                          const QStyleOptionViewItem &option,
                                          const QModelIndex &index) const
    {
    	QRect rc = option.rect;
    	editor->setGeometry(rc);
    }
    void CheckBoxDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
    {
    	if (index.column() == 0)
    	{
    		QCheckBox * pBox = static_cast<QCheckBox *>(editor);
    		pBox->update();
    		bool checked = pBox->isChecked();
    
    		model->setData(index, checked, Qt::EditRole);
    	}
    	else
    	{
    		QComboBox * pBox = static_cast<QComboBox *>(editor);
    		pBox->update();
    		QString str = pBox->currentText();
    
    		model->setData(index, str, Qt::EditRole);
    	}
    }
    void CheckBoxDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
    {
    	int x = option.rect.x();
    	int y = option.rect.y();
    	QVariant value = index.model()->data(index, Qt::DisplayRole);
    	if (index.column() == 0)
    	{
    		bool checked = value.toBool();
    		QStyleOptionButton style;
    		style.rect = QRect(x, y + 8, 12, 12);
    		style.state |= QStyle::State_Enabled;
    		style.state |= checked ? QStyle::State_On : QStyle::State_Off;
    		QApplication::style()->drawControl(QStyle::CE_CheckBox, &style, painter);
    	}
    	else
    	{
    		QStyleOptionComplex style;
    		style.rect = QRect(x, y + 8, 12, 12);
    		style.state = QStyle::State_HasFocus;
    		style.state |= QStyle::State_Enabled;
    		QApplication::style()->drawComplexControl(QStyle::CC_ComboBox, &style, painter);
    	}
    }
    bool CheckBoxDelegate::eventFilter ( QObject * editor, QEvent * event )
    {
    	if (event->type() == QEvent::Wheel)
    	{
    		QString clsName = editor->metaObject()->className();
    		if (clsName.compare("QCheckBox") == 0)
    		{
    			QObject * obj = editor->parent();
    			while(obj)
    			{
    				qDebug() << obj;
    				obj = obj->parent();
    			}
    			return true;
    		}
    		qDebug() << editor;
    	}
    	//qDebug() << event->type() << editor;
    	return QStyledItemDelegate::eventFilter(editor, event);
    }
    

    The code snippet to initialize QTabview is as below:

    	m_pModel2 = new FormulaListModel(this);
    	ui.lvContainer->setModel(m_pModel2);
    	ui.lvContainer->setShowGrid(false);
    
    	QHeaderView * pHeader = ui.lvContainer->horizontalHeader();
    	pHeader->hide();
    	pHeader = ui.lvContainer->verticalHeader();
    	pHeader->hide();
    
    	ui.lvContainer->setColumnWidth(0, 80);
    	ui.lvContainer->setColumnWidth(1, 150);
    	ui.lvContainer->setColumnWidth(2, 150);
    	ui.lvContainer->setColumnWidth(3, 150);
    	ui.lvContainer->setItemDelegate(new CheckBoxDelegate(this));
    
    	for (int i = 0;i < m_pModel2->rowCount();i ++)
    	{
    		ui.lvContainer->openPersistentEditor(m_pModel2->index(i, 0));
    		ui.lvContainer->openPersistentEditor(m_pModel2->index(i, 1));
    		ui.lvContainer->openPersistentEditor(m_pModel2->index(i, 2));
    		ui.lvContainer->openPersistentEditor(m_pModel2->index(i, 3));
    	}
    	ui.lvContainer->updateGeometry();
    

    Code snippet to insert row is as below:

    	m_pModel2->AddDevName("dev1");
    	m_pModel2->AddDevName("dev2");
    	m_pModel2->AddOperator("+");
    	m_pModel2->AddOperator("-");
    	m_pModel2->AddFormula(0, 0, 0, false);
    

    When I execute these code, only a empty QCheckBox with a equal symbol is display. The text and other QComboBox doesn't appear.
    I am a freshman of Qt. I don't know how to make it work well. Please help me with kind. Thx!



  • Part of problem had been resolved. I use the following code to add item:

    	m_pModel2->AddFormula(1, 1, 0, false);
    	for (int i = 0;i < m_pModel2->rowCount();i ++)
    	{
    		ui.lvContainer->openPersistentEditor(m_pModel2->index(i, 0));
    		ui.lvContainer->openPersistentEditor(m_pModel2->index(i, 1));
    		ui.lvContainer->openPersistentEditor(m_pModel2->index(i, 2));
    		ui.lvContainer->openPersistentEditor(m_pModel2->index(i, 3));
    	}
    

    And the item can be displayed as I wanted. But another problem is still exist: after I add a new item, the text I had selected for QComboBox is lost. How to reserve them till I finish the operation?


Log in to reply