[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