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

Ch'Gans chgans at gna.org
Sun Jun 8 03:55:48 CEST 2014


Hi Adam,

Thank you for your code snip, I used the persistent editor approach, as 
my table will never contains more than a dozen rows, I think this is OK.

Another thing I have been fighting with, was to have my editor centered 
in the table cells, I found 2 interesting results [1], [2] But I didn't 
like them (too much code). My solution is amazingly more simple and 
gives me perfect result, I only override updateEditorGeometry() and 
paint() in my ItemDelegate this way:

void updateEditorGeometry(QWidget *editor,
                           const QStyleOptionViewItem &option,
                           const QModelIndex &index) const
{
     Q_UNUSED(index)
     // Center the editor in the cell
     QRect geom = QStyle::alignedRect(option.direction, Qt::AlignCenter,
                                      editor->sizeHint(),
                                      option.rect);
     editor->setGeometry(geom);
}

void paint(QPainter *painter, const QStyleOptionViewItem &option,
            const QModelIndex &index) const
{
     // Don't paint anything
     Q_UNUSED(painter)
     Q_UNUSED(option)
     Q_UNUSED(index)
     return;
}

Krys,

[1] 
https://stackoverflow.com/questions/2785434/how-to-interact-with-checkbox-actions-qtableview-with-qstandarditemmodel/4451324#4451324
[2] 
https://qt-project.org/faq/answer/how_can_i_align_the_checkboxes_in_a_view

On 07/06/14 01:16, Adam Light wrote:
> [Replying to the list this time as well]
>
>
> On Thu, Jun 5, 2014 at 7:38 PM, Christian Gagneraud <chgans at gna.org
> <mailto: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();
>
> }
>
>
>

-- 
QtCreator/qmakeparser.cpp:42
////////// Parser ///////////
#define fL1S(s) QString::fromLatin1(s)
namespace { // MSVC2010 doesn't seem to know the semantics of "static" ...



More information about the Interest mailing list