PDA

View Full Version : Model/Delegate/Proxy



skyline2000
9th March 2011, 15:39
Hello together I'm experimenting with qt and have some questions about this whole
Model-Delegate-Proxy stuff.

What I want to achieve is to show a list of Persons in a QListView, with the ability of
filtering, and showing letter-captions, (Like many List-Controls on mobileOS) and writing the whole information for a person in 1 cell.

-----------------------
|A |
-----------------------
|Abigail Familly-Name |
|Audrey Familly-Name |
-----------------------
|C |
-----------------------
|Christian Familly-Name|
-----------------------
|D |
-----------------------
|Daniel Familly-Name |
-----------------------

I have a Class: Person where I have the structure of the information (Name,Famillyname,day of b.... aso.)

On the MODEL side I have a QAbstractListModel


..........
explicit PersonModel(QObject *parent = 0);

int columnCount(const QModelIndex &parent) const;
int rowCount( const QModelIndex &index = QModelIndex()) const;

QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
void FillData();

private:
Q_DISABLE_COPY(PersonModel);
QList<Person*> Persons;
...............

My data() function looks like this:


QVariant PersonModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
{
qRegisterMetaType<Person>("Person");
QVariant v;
v.setValue<CPerson>(*Persons.at(index.row()));
return v;
}
return QVariant();
}

Since I want to write different parts of the person class in on cell I return the
whole structure in a QVariant.

On the DELEGATE side my paint looks like this:


void PersonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() == 0) {
Person entry =index.model()->data(index).value<Person>();
painter->setFont( QFont("Arial",14,QFont::Bold));
QRect NameRect = option.rect;
NameRect.setLeft(5);
painter->drawText(NameRect,Qt::AlignLeft,entry.GetName());
NameRect.setLeft(0);
NameRect.setRight(NameRect.width()-5);
painter->setFont( QFont("Arial",14,QFont::Cursive));
painter->drawText(NameRect,Qt::AlignRight,entry.GetSurename ());
}
}

Here I'm placing Name and Surename.

On the proxy side I have QSortFilterProxyModel.


bool MySortFilterProxyModel::lessThan(const QModelIndex &left,const QModelIndex &right) const
{
Person leftData = sourceModel()->data(left).value<Person>();
Person rightData = sourceModel()->data(right).value<Person>();

QString leftString = leftData.GetName();
QString rightString = rightData.GetName();

return QString::localeAwareCompare(leftString, rightString) < 0;
}

bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const
{
QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
Person data = sourceModel()->data(index0).value<Person>();
QString strData = data.GetName();
return (strData.contains(filterRegExp()));
}

This stuff works so far.

Now I have 2 problems.
1. If I set the proxy filter e.g. on 'Da' the proxy is also filtering-out the Letter-Caption 'D', so that the List looks like
-----------------------
|Daniel Familly-Name |
-----------------------
What I have tried is to add a additional flag in my person class (Letter Caption yes/ no) and than to check this flag in filterAcceptsRow(). But than the list looks like this

-----------------------
|A |
-----------------------
-----------------------
|C |
-----------------------
-----------------------
|D |
-----------------------
|Daniel Familly-Name |
-----------------------
The letter-captions should only be drawn when there is a name.

My 2. problem is:
How can I convince Paint() and sizeHint() to draw this letter-captions in a
different way. (height of cell,BG-Color)?

Anyhow, I think that UserRoles could be the solution for my problems,
but my experiments with UserRoles were not really successful.

Have you any ideas how I could implement something like this, or is there
a better way of doing this, than the way I tried?

Thanks!

wysota
9th March 2011, 16:13
There are at least two possible approaches. One is to determine in the delegate and in the proxy whether the index contains the address card or the prefix header and act accordingly in paint() and in filterAcceptsRow(). Another is to make your model a tree model where prefixes are at level 0 of the model and address cards at level 1 and only filter out items at level 1 (adjusting filterAcceptsRow accordingly) and painting items differently in paint() depending on their level in the hierarchy. You could either use QTreeView with a customized tree drawing to get rid of branches and indentation or a QListView with a proxy model that flattens the original model (but painting and filtering should still be aware of the underlying model).