PDA

View Full Version : Creating Custom Widgets With QStyleItemDelegate



smhall316
18th April 2013, 03:04
I am having a hard time getting custom delegates to work. I have a QTreeView where each item could require a separate input widget. One could need a simple QLineEdit, another could require a QComboBox, while others may require a custom widget which contains a QLabel next to a QPushButton. I can get the simple widgets to work with QStyledItemDelegate or QItemDelegate, but when I try to show my custom widget (QLabel next to a QPushButton) in createEditor, nothing shows up. Is it possible to show custom widgets as delegates? I have seen a lot of posts reference the paint() method in the delegate class, but I am not sure if I am suppose to draw the widget with the paint method?? Any ideas?

Thanks

Sorry, in the first line I say custom delegates, I meant to say custom widgets working in delegates

Santosh Reddy
18th April 2013, 09:49
Is it possible to show custom widgets as delegates?
Yes.


I have seen a lot of posts reference the paint() method in the delegate class, but I am not sure if I am suppose to draw the widget with the paint method?
For your case of composite widget, re-implementig paint() is not required.


I can get the simple widgets to work with QStyledItemDelegate or QItemDelegate, but when I try to show my custom widget (QLabel next to a QPushButton) in createEditor, nothing shows up.
The problem may be with the cell size in QTreeView, which may not be enough to fit the custom widget that was created using createEditor(). Try to create the editor widget with no parent, so that when editing is trigerred, you should see the custom composite widget pop up.

I have put togeather a small example, not very clean but works.



#include <QtGui>
#include <QApplication>

class Editor : public QWidget
{
Q_OBJECT

public:
explicit Editor(const QModelIndex & index, QWidget * parent)
: QWidget(parent)
, mLineEdit(new QLineEdit)
, mText(index.data().toString())
{
QHBoxLayout * hBoxLayout = new QHBoxLayout(this);
QPushButton * pushButton = new QPushButton("Apply");
hBoxLayout->addWidget(mLineEdit,2);
hBoxLayout->addWidget(pushButton,1);
connect(pushButton, SIGNAL(clicked()), SLOT(updateText()));
mLineEdit->setText(mText);
}

public:
QString text(void) const
{
return mText;
}

signals:
void textChanged(const QString & text);

public slots:
void setText(const QString & text)
{
mText = text;
mLineEdit->setText(text);
}

private slots:
void updateText(void)
{
mText = mLineEdit->text();
emit textChanged(mText);
}

private:
QLineEdit * mLineEdit;
QString mText;
};

class StyledItemDelegate : public QStyledItemDelegate
{
public:
explicit StyledItemDelegate(QObject * parent = 0)
: QStyledItemDelegate(parent)
{
;
}

virtual QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
return new Editor(index, parent);
}

virtual QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
{
return Editor(index, 0).sizeHint();
}

protected:
virtual void setEditorData(QWidget * editor, const QModelIndex & index) const
{
static_cast<Editor*>(editor)->setText(index.data().toString());
}

virtual void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
static_cast<Editor*>(editor)->setGeometry(option.rect);
}

virtual void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
{
model->setData(index, static_cast<Editor*>(editor)->text());
}
};

void addData(QStandardItemModel * model)
{
model->setRowCount(10);
model->setColumnCount(2);

for(int r = 0; r < model->rowCount(); r ++)
for(int c = 0; c < model->columnCount(); c++)
model->setData(model->index(r, c), QString("Item-%1,%2").arg(r).arg(c), Qt::DisplayRole);
}

int main(int argc, char ** argv)
{
QApplication app(argc, argv);

QTreeView treeView;
QStandardItemModel model;
StyledItemDelegate delegate;

addData(&model);

treeView.setModel(&model);
treeView.setItemDelegate(&delegate);
treeView.setEditTriggers(treeView.DoubleClicked);
treeView.show();

return app.exec();
}

#include "main.moc"

smhall316
18th April 2013, 11:15
That was exactly the problem. I tried without parenting the custom widget and sure enough it showed up. Then I implemented the sizeHint and parented the custom widget and I was able to see the custom widget show up in the appropriate cell. Of course after I did the size hint I had very tall rows, but at least it is getting me in the right direction.

On a sizing note, I assume I can resize my widget to fit in the default size of the cell. Would that be the way to fit the custom widget, or is there a more elegant way?

Many thanks for your help!!

Santosh Reddy
18th April 2013, 11:26
On a sizing note, I assume I can resize my widget to fit in the default size of the cell. Would that be the way to fit the custom widget, or is there a more elegant way?
It depends, if you can make the widget fit cell, else you may need to use sizeHint() of delegate and change the cell size based on whether it is being edited, or just being displayed.

smhall316
18th April 2013, 20:47
Well I can use the size hint as you suggest, but it causes the row heights to increase too much. I can pass the row height to my widget I am using in the delegate. I even size the widget to match the row height that is currently in the treeview, however the widget seems to be offset in that index and does not show the whole thing.

I have explored setting sizeHints, but I don't see how a user programmitically sets a size hint. Are you not allowed to dictate the size of your widgets?

Added after 9 minutes:

Nevermind my last question. It appears my problem has to do with my margins used in the layout. Simply adjusting setContentsMargins(0,0,0,0) fixed the problem!!