Unsolved Setting right the size and geometry of custom QStyledItemDelegate
-
Hello,
I'm trying to figure out how to set right the size and the geometry of a QStyledItemDelegate. The delegate uses a subclassed QTextEdit which adjusts its height dynamically when the users types or deletes text. This is what I've done so far:
In the subclassed QTextEdit, I'm using the following code:
CellEditor::CellEditor(const QModelIndex &index, QWidget *parent) : QTextEdit(parent), m_text(index.data(Qt::DisplayRole).toString()) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QTextDocument *doc = new QTextDocument(m_text,this); setDocument(doc); document()->setDocumentMargin(4); //I want everything to appear fine even if I change the margin... setFrameStyle(0); connect(this,SIGNAL(textChanged()),this,SLOT(updated())); } void CellEditor::updated() { const qreal frameBorder = frameWidth(); //currently it's 0 const qreal requiredHeight = document()->size().height(); const qreal availableHeight = size().height() - frameBorder; if (requiredHeight != availableHeight) { resize(size().width(), requiredHeight); } }
In the delegate, I simply create and return the widget in the createEditor function passing the parent and index arguments, I implement the setEditorData and setModelData, and then I try to set the size and geometry like this:
void CellEditorDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const { editor->setGeometry(option.rect); } QSize CellEditorDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItemV4 optionV4 = option; initStyleOption(&optionV4, index); QTextDocument doc; doc.setPlainText(optionV4.text); doc.setTextWidth(optionV4.rect.width()); return QSize(doc.idealWidth()+2, doc.size().height()+doc.documentMargin()+2); //+2 to adjust for QTableView's grid line widths } void CellEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (option.state & QStyle::State_Enabled) { const QRect rect(option.rect.x()+4,option.rect.y()+4,option.rect.width()-6,option.rect.height()-6); painter->drawText(rect,Qt::TextWordWrap,index.data().toString()); //+4 seems to adjust for the current document's margins, -6 seems to adjust for the current document margins and the QTableView's grid line widths } else { QStyledItemDelegate::paint(painter,option,index); } }
In order to notify the model and the view for the size change, I use an event filter:
bool CellEditorDelegate::eventFilter(QObject *object, QEvent *event) { bool result = QStyledItemDelegate::eventFilter(object,event); QWidget *editor = qobject_cast<QWidget*>(object); if(editor) { if(event->type() == QEvent::Resize) { emit commitData(editor); } } return result; }
Here is a screenshot so I can explain better what I want to achieve and what's wrong right now:
When the user clicks on a cell to edit the text, I want everything to stay in its current position without any glitches (e.g. slight repositioning of the QTextEdit, different word wrapping, slight overlapping on the grid line, etc). This mostly works ok right now, with the exception that in some cases, after resizing the app window, a word will appear very close to the right edge (although in the paint function it seems that I draw the text with enough margins) so when the user enters the cell the word wrapping will change creating a visual glitch.
My concern is that I want to get rid of the hard-coded values in the paint function and generally get a better grasp of whole process.
Many thanks in advance for any hints and advice.