[Interest] QAbstractTableModel: ItemDelegate for both display and edit role

Adam Light aclight at gmail.com
Fri Jun 6 15:16:37 CEST 2014


[Replying to the list this time as well]


On Thu, Jun 5, 2014 at 7:38 PM, Christian Gagneraud <chgans at gna.org> wrote:

> Hi all,
>
> I would like to use item delegates to both display and edit items using
> QAbstractTableModel/QTableView.
> I was able to get my specialised widget used when the user *edit* the
> field but I would like to have the same widget used for displaying the
> field as well.
>
> My QStyledItemDelegate based delegated reimplements these functions:
> - createEditor
> - setEditorData
> - setModelData
> - updateEditorGeometry
>
> I would like to know if the only way to have my widget used for both the
> display role and the edit role is to reimplement as well paint() and
> sizeHint(). If not, can anyone point me at docs or example?
>

You could do what we do in our application and set all cells (or certain
cells) of the view to use persistent editors (
http://qt-project.org/doc/qt-4.8/qabstractitemview.html#openPersistentEditor
).

If you go that way, it's a bit tricky because you need to call
openPersistentEditor() in a number of different situations. Here are some
methods from WMTableView, a relatively simple QTableView subclass we use in
our application to handle this situation:

/**

	\brief Constructs a WMTableView with with parent \a parent.

*/

WMTableView::WMTableView(QWidget* parent) :

	QTableView(parent),

	_nextAndPreviousMoveToEditableCell(true),

	_persistentEditorUpdateTimerStarted(false),

	_updatingPersistentEditorColumns(false)

{

	// Set a style sheet to provide a bit of spacing between cells. This
is necessary

	// so that the error frame around any widgets in the table is not covered

	// up on Windows by widgets in adjacent cells.

	setStyleSheet(QLatin1String("WMTableView::item {margin: 2px;}"));


	// Force the persistence of editors in each cell to update when

	// the number of rows or columns changes or the model is reset.

	connect(verticalHeader(), SIGNAL(sectionCountChanged(int,int)), this,
SLOT(_scheduleUpdateOfPersistentEditorColumns()));

	connect(horizontalHeader(), SIGNAL(sectionCountChanged(int,int)),
this, SLOT(_scheduleUpdateOfPersistentEditorColumns()));

}


/**

	\brief Sets all columns in \a colList to use persistently open editors.


	All columns not in \a colList will be treated as not persistently open editors.

*/

void WMTableView::setPersistentEditorColumns(const QList<int> colList) {

	_persistentEditorColumns = colList;

	_scheduleUpdateOfPersistentEditorColumns();

}


/**

	\reimp

*/

void WMTableView::setModel(QAbstractItemModel *newModel) {

	// We need to make sure that
_scheduleUpdateOfPersistentEditorColumns() is called

	// when the model is reset.


	QAbstractItemModel* oldModel = model();


	if (newModel == oldModel) {

		return;

	}


	QTableView::setModel(newModel);


	// Disconnect, if necessary.

	if (oldModel) {

		// Disconnect connections to old model.

		disconnect(oldModel, SIGNAL(modelReset()), this,
SLOT(_scheduleUpdateOfPersistentEditorColumns()));

		disconnect(oldModel, SIGNAL(layoutChanged()), this,
SLOT(_scheduleUpdateOfPersistentEditorColumns()));

		disconnect(oldModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(_scheduleUpdateOfPersistentEditorColumns()));

		disconnect(oldModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
this, SLOT(_scheduleUpdateOfPersistentEditorColumns()));

		disconnect(oldModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT(_onModelsDataChanged(QModelIndex,QModelIndex)));

	}


	// Make new connections, if necessary.

	if (newModel) {

		connect(newModel, SIGNAL(modelReset()), this,
SLOT(_scheduleUpdateOfPersistentEditorColumns()));

		connect(newModel, SIGNAL(layoutChanged()), this,
SLOT(_scheduleUpdateOfPersistentEditorColumns()));

		connect(newModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this,
SLOT(_scheduleUpdateOfPersistentEditorColumns()));

		connect(newModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
this, SLOT(_scheduleUpdateOfPersistentEditorColumns()));

		connect(newModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT(_onModelsDataChanged(QModelIndex,QModelIndex)));

	}

}


/**

	\brief Opens or closes persistent editors in each cell of the view as
appropriate.


	Do not call this method directly. Call
_scheduleUpdateOfPersistentEditorColumns() instead.

*/

void WMTableView::_updatePersistentEditorColumns() {

	// This slot should only be called by the single shot timer created

	// in _scheduleUpdateOfPersistentEditorColumns() to

	// improve performance and try to prevent crashes.

	Q_ASSERT(_persistentEditorUpdateTimerStarted);


	_persistentEditorUpdateTimerStarted = false;


	if (_updatingPersistentEditorColumns) {

		// Block recursion, though this should never happen (I think).

		// If this does happen, then the single shot timer that calls this
method needs to be recreated.

		Q_ASSERT(0);

		return;

	}


	_updatingPersistentEditorColumns = true;

	QAbstractItemModel* theModel = model();

	if (theModel) {

		int numRows = model()->rowCount(rootIndex());

		int numCols = model()->columnCount(rootIndex());

		for (int colNum = 0; colNum < numCols; ++colNum) {

			int columnXPosition = columnViewportPosition(colNum);

			bool columnIsPersistent = _persistentEditorColumns.contains(colNum);

			for (int rowNum = 0; rowNum < numRows; ++rowNum) {

				QPoint cellPoint(columnXPosition, rowViewportPosition(rowNum));

				QModelIndex childIndex = indexAt(cellPoint);

				if (childIndex.isValid()) {

					if (columnIsPersistent && ((childIndex.flags() &
Qt::ItemIsEditable) != 0)) {

						openPersistentEditor(childIndex);

						QWidget* editor = indexWidget(childIndex);

						QLineEdit* le = qobject_cast<QLineEdit*>(editor);

						if (le) {

							if (currentIndex() != childIndex) {

								le->deselect();

							}

						}

					}

					else {

						closePersistentEditor(childIndex);

					}

				}

			}

		}

	}

	_updatingPersistentEditorColumns = false;

}


/**

	\brief Schedules/queues an update of the persistent editor columns

	if one is not already scheduled.


	Calling this slot instead of _updatePersistentEditorColumns() directly

	is more efficient and can prevent crashes that can result when

	_updatePersistentEditorColumns() is called multiple times in a row.

*/

void WMTableView::_scheduleUpdateOfPersistentEditorColumns() {

	if (!_persistentEditorUpdateTimerStarted) {

		QTimer::singleShot(0, this, SLOT(_updatePersistentEditorColumns()));

		_persistentEditorUpdateTimerStarted = true;

	}

}


/**

	\brief Opens/closes or updates persistent editors throughout the view.

*/

void WMTableView::_onModelsDataChanged(const QModelIndex &first, const
QModelIndex &last) {

	Q_UNUSED(first);

	Q_UNUSED(last);

	_scheduleUpdateOfPersistentEditorColumns();

}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20140606/6d04cefa/attachment.html>


More information about the Interest mailing list