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

Filip Piechocki fpiechocki at gmail.com
Fri Jun 6 15:29:50 CEST 2014


But persistent editors are quite heavy. Another way is to paint the
"screenshot" of your editor in the cell with in a paint() method of your
delegate. So you can have just one hidden instance of your widget, set data
to it and use QWidget::render() to paint it in the cell.

BR,
Filip Piechocki


On Fri, Jun 6, 2014 at 3:16 PM, Adam Light <aclight at gmail.com> wrote:

> [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();
>
> }
>
>
>
>
> _______________________________________________
> Interest mailing list
> Interest at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/interest
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20140606/b77b7b85/attachment.html>


More information about the Interest mailing list