PDA

View Full Version : Item Delegate Painting



stevey
8th May 2008, 03:45
I'm writing a delegate that I wish to use integrate with Drag and Drop on a QListView.
The idea is that if people drag a file from the desktop into the application the filename will be copied to the clipboard, then as they drag the mouse over items, either in the list, if they are hovering directly over the item, then when they release they will be asked if they want to replace the existing item, or if it's within a range of pixels from the top or bottom of the item, then I want to draw a red line between the items, the "insert" the dragged filename to this location.

As a start I've sub-classed QAbstractItemDelegate and implemented "paint" and "sizeHint".
I thought to begin with I'd just draw a straight line through the text on the selected item, so I hardcoded some values in, basically drawLine(left, height of item / 2, right, height of item / 2). This works fine, regardless of the item I click on the entire list gets cleared and the red line gets drawn through the first item.

Can anyone suggest what I need to add to the following code to draw through the item selected and retain the item data, I'm guessing I need to use the QModelIndex parameter.



#ifndef DRAGDROPLISTITEMDELEGATE_H
#define DRAGDROPLISTITEMDELEGATE_H

#include <QAbstractItemDelegate>


class DragDropListItemDelegate : public QAbstractItemDelegate
{
Q_OBJECT

public:
DragDropListItemDelegate(QObject* parent = 0);

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex &index) const;
void setEditorData(QWidget* editor, const QModelIndex& index) const;
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const;
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;

};

#endif // DRAGDROPLISTITEMDELEGATE_H




#include "DragDropListItemDelegate.h"

#include <QSpinBox>
#include <QLineEdit>
#include <QModelIndex>
#include <QString>
#include <QColor>
#include <QPainter>
#include <QSize>

DragDropListItemDelegate::DragDropListItemDelegate (QObject* parent)
{

}

QWidget* DragDropListItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex &index) const
{
QLineEdit* editor = new QLineEdit(parent);

return editor;
}

void DragDropListItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
QString value = index.model()->data(index, Qt::DisplayRole).toString();
QLineEdit* lineEdit = static_cast<QLineEdit*>(editor);
lineEdit->setText( value );

}

void DragDropListItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
QLineEdit* lineEdit = static_cast<QLineEdit*>(editor);
QString value = lineEdit->text();

model->setData(index, value, Qt::EditRole);
}

void DragDropListItemDelegate::updateEditorGeometry(QWi dget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
editor->setGeometry(option.rect);
}

void DragDropListItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
painter->drawLine( option.rect.left(), option.rect.height() / 2, option.rect.right(), option.rect.height() / 2 );
painter->setPen( QColor(255, 0, 0) );

}

QSize DragDropListItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
return QSize(10, 10);
}



Also, the paint event is called in this case when I click an item. Will it also fire when I'm dragging over an item?

wysota
8th May 2008, 09:52
Based on what I know the default behaviours of all the views is like you describe it, so there is no need for a custom delegate. Just enable drag & drop for your model and view and maybe reimplement dropEvent() to pop up the replacement dialog before calling the base class implementation.

stevey
8th May 2008, 14:11
From a test a did in the past I recall that there wasn't a "guide" (the red line) indicating where the item was going to be placed, so I figured I'd need a delegate to do that.

I actually want it be be like in Excel when you move rows around. If you drag a row in between you get a really wide H shape on the division between the rows in a greyed out colour. I want that in say red, and possibly even slide what's below the insertion point down a row height as a really clear indication of where it's going, kind of like the way dock widgets slide apart to make a space.

The software project I'm working on is (intended to be) a better version of a system I supported a few years ago. Whilst I'm working on the re-invention I want to make the user experience as easy and obvious as possible.

I'll try getting the drag and drop done first and see how that behaves, then attempt to implement this delegate if it doesn't work.
If I do need the delegate, how do I work around my original question? Do I need to loop through each QModelIndex, get the data() member then paint the text manually onto the QPainter context provided, essentially managing the entire rendering process?
Maybe I just need to look at the QItemDelegate implementation.

wysota
9th May 2008, 07:37
From a test a did in the past I recall that there wasn't a "guide" (the red line) indicating where the item was going to be placed, so I figured I'd need a delegate to do that.
There is, just set the showDropIndicator property to true.


I actually want it be be like in Excel when you move rows around. If you drag a row in between you get a really wide H shape on the division between the rows in a greyed out colour. I want that in say red, and possibly even slide what's below the insertion point down a row height as a really clear indication of where it's going, kind of like the way dock widgets slide apart to make a space.

In that case delegates won't help you. You have to implement it in the view. The delegate renders a single item, not "a row of items" or "something around items".