Question

So what I want is a qlistview that displays selectable widgets(label that displays an image and text for a button(widget is a qwidget based widget which has a horizontal layout with a QLabel and a QPushButton)). The model should store image path and button text for each item(which doesn't seem to be a problem). I successfully created a QListView derived widget but it displays only the first list item(which is the custom widget) and it's not selectable. I created a custom model, view and delegate but I can't figure out what to do to show widgets on all the list items, not just first. Here is the complete source code link: SOURCE CODE LINK

I ran the application with a list of 5 widgets items and with a list of 1 widget item separatly. And I think it adds the widgets but it overlaps all of them on the first one(the 5 items build has a denser shadow on the button):

5 widgets on the list: Widget compiled and ran with 5 widget items defined in the loop

1 widget in the list: Widget compiled and ran with 1 widget item defined in the loop

As you can see there is a difference in the shadow.

Here is another copy of the code:

Delegate.h Here is the code for the delegate:

#include <QtGui>
#include <QAbstractItemDelegate>

class WidgetDelegate : public QAbstractItemDelegate
{
public:
    WidgetDelegate(QObject *parent = 0);

    void paint(QPainter *painter,
               const QStyleOptionViewItem &option,
               const QModelIndex &index) const;

    QSize sizeHint(const QStyleOptionViewItem &option,
                  const QModelIndex &index) const;

};

Delegate.cpp

#include <QtGui>

#include "Delegate.h"
#include "Profile.h"

WidgetDelegate::WidgetDelegate(QObject *parent)
    : QAbstractItemDelegate(parent)
{ }

void WidgetDelegate::paint(QPainter */*painter*/,
                           const QStyleOptionViewItem &/*option*/,
                           const QModelIndex &/*index*/) const
{
}

QSize WidgetDelegate::sizeHint(const QStyleOptionViewItem &/*option*/,
                              const QModelIndex &/*index*/) const
{
    return QSize(ProfileItem().geometry().width(), ProfileItem().geometry().height());
}

Model.h

#ifndef MODEL_H
#define MODEL_H

#include <QStringList>
#include <QAbstractListModel>
#include <QList>
#include "Profile.h"

class StringListModel : public QAbstractListModel
{
    Q_OBJECT

public:
    StringListModel(const QStringList &strings, QObject *parent = 0)
        : QAbstractListModel(parent), stringList(strings) {}

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

private:
    QStringList stringList;
};

#endif // MODEL_H

Model.cpp

#include "Model.h"
#include <QVariant>

int StringListModel::rowCount(const QModelIndex &/*parent*/) const
{
    return stringList.count();
}

QVariant StringListModel::data(const QModelIndex &/*index*/,
                               int /*role*/) const
{
}

QVariant StringListModel::headerData(int /*section*/,
                                     Qt::Orientation /*orientation*/,
                                     int /*role*/) const
{
}

Prefs.h Widget containing the list view:

#ifndef PREFERENCES_H
#define PREFERENCES_H

#include "Model.h"
#include <QDialog>

class QPushButton;
class ProfileItem;
class QVBoxLayout;
class View;
class StringListModel;

class Preferences : public QDialog
{
public:
    Preferences(QWidget *parent = 0);

private:
    QVBoxLayout *m_pVerticalLayout;

    View *myList;
    QPushButton *button;
    ProfileItem *item;
    StringListModel *customModel;
};

#endif // PREFERENCES_H

Prefs.cpp

#include "Profile.h"

#include <QPixmap>
#include <QHBoxLayout>
#include <QBitmap>
#include <QMessageBox>

ProfileItem::ProfileItem(QWidget *parent) :
    QWidget(parent)
{
    pixmap = QPixmap(":/avatar");

    m_avatarImageLabel.setPixmap(pixmap);
    m_avatarImageLabel.setMask(pixmap.mask());
    m_avatarTextButton.setText("Test");
    connect(&m_avatarTextButton, SIGNAL(clicked()), this, SLOT(buttonPushed()));

    m_pHorizontalLayout = new QHBoxLayout;

    m_pHorizontalLayout->addWidget(&m_avatarImageLabel);
    m_pHorizontalLayout->addWidget(&m_avatarTextButton);

    setLayout(m_pHorizontalLayout);
}

void ProfileItem::setAvatarImage(const QString &avatarImage)
{
    pixmap = QPixmap(avatarImage);
    m_avatarImageLabel.setPixmap(pixmap);
    m_avatarImageLabel.setMask(pixmap.mask());
}

void ProfileItem::setAvatarName(const QString &avatarName)
{
    m_avatarTextButton.setText(avatarName);
}

void ProfileItem::buttonPushed()
{
    QMessageBox msg;
    msg.setText("Button was pushed!");
    msg.exec();
}

Profile.h Widget that has to be used as list item

#ifndef PROFILEITEM_H
#define PROFILEITEM_H

#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QPixmap>

class QHBoxLayout;

class ProfileItem : public QWidget
{
    Q_OBJECT

public:
    explicit ProfileItem(QWidget *parent = 0);

public slots:
    void setAvatarImage(const QString &avatarImage);
    void setAvatarName(const QString &avatarName);
    void buttonPushed();

private:
    QPixmap pixmap;
    QLabel m_avatarImageLabel;
    QPushButton m_avatarTextButton;

    QHBoxLayout *m_pHorizontalLayout;

};

#endif // PROFILEITEM_H

Profile.cpp

#include "Profile.h"

#include <QPixmap>
#include <QHBoxLayout>
#include <QBitmap>
#include <QMessageBox>

ProfileItem::ProfileItem(QWidget *parent) :
    QWidget(parent)
{
    pixmap = QPixmap(":/avatar");

    m_avatarImageLabel.setPixmap(pixmap);
    m_avatarImageLabel.setMask(pixmap.mask());
    m_avatarTextButton.setText("Test");
    connect(&m_avatarTextButton, SIGNAL(clicked()), this, SLOT(buttonPushed()));

    m_pHorizontalLayout = new QHBoxLayout;

    m_pHorizontalLayout->addWidget(&m_avatarImageLabel);
    m_pHorizontalLayout->addWidget(&m_avatarTextButton);

    setLayout(m_pHorizontalLayout);
}

void ProfileItem::setAvatarImage(const QString &avatarImage)
{
    pixmap = QPixmap(avatarImage);
    m_avatarImageLabel.setPixmap(pixmap);
    m_avatarImageLabel.setMask(pixmap.mask());
}

void ProfileItem::setAvatarName(const QString &avatarName)
{
    m_avatarTextButton.setText(avatarName);
}

void ProfileItem::buttonPushed()
{
    QMessageBox msg;
    msg.setText("Button was pushed!");
    msg.exec();
}

View.h

#ifndef VIEW_H
#define VIEW_H

#include <QListView>

class View : public QListView
{
public:
    View();

    void setModel(QAbstractItemModel *model);
    QSize sizeHint();
};

#endif // VIEW_H

View.cpp

#include "View.h"
#include "Profile.h"

View::View()
{
    viewport()->setAutoFillBackground(false);
    setSelectionMode(QAbstractItemView::SingleSelection);
}

void View::setModel(QAbstractItemModel* model)
{
    QListView::setModel(model);

    for (int i = 0; i < 5; ++i)
    {
        QModelIndex index = model->index(i, 0);

        ProfileItem* widget = new ProfileItem();
        setIndexWidget(index, widget);
    }
}

QSize View::sizeHint()
{
    return QSize(ProfileItem().width(), ProfileItem().height());
}

Can anyone help me populate all the list items with the wanted widget or tell me what i'm doing wrong or some hints? Is it possible in qt to have widgets as list/table items in this MVC style? I couldn't find any references for achieving this anywhere. Searched in C++ GUI Programming with Qt, Advanced Qt Programming, Introduction to Design Patterns in C++ with Qt 4 and a few more places on the internet but couldn't find anything related to QAbstractItemView::setIndexWidget which I think it's the method that adds the widget as a list view item.

Thank you!

Was it helpful?
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top