Qt Model View Controller中的视图项目是QWidget。

4
我想要一个显示可选小部件的 qlistview(包括显示图像和按钮文本的标签小部件)。该模型应存储每个项目的图像路径和按钮文本。我成功创建了一个 QListView 派生小部件,但它仅显示第一项(自定义小部件),且无法选择。我创建了一个自定义模型、视图和代理,但我不知道如何在所有列表项上显示小部件,而不仅是第一个。 以下是完整的源代码链接:SOURCE CODE LINK 我分别使用了包含 5 个小部件项目和包含 1 个小部件项目的列表来运行应用程序。我认为它确实添加了这些小部件,但是所有的小部件都重叠在第一个小部件上(包含 5 个小部件的版本中按钮有更浓的阴影效果):
包含 5 个小部件的列表: Widget compiled and ran with 5 widget items defined in the loop 包含 1 个小部件的列表: Widget compiled and ran with 1 widget item defined in the loop 您可以看到阴影存在差异。
以下是代码备份:

Delegate.h 这是 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
包含列表视图的小部件:

#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 需要用作列表项的小部件

#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());
}

有谁能帮我用所需的小部件填充所有列表项,或告诉我我做错了什么或给我一些提示吗?在qt中是否有可能以这种MVC风格将小部件作为列表/表项?在任何地方都找不到实现此功能的参考资料。在《C ++ GUI编程与Qt》、《高级Qt编程》、《C ++中的设计模式入门》以及互联网上的其他几个地方搜索过,但找不到与QAbstractItemView ::setIndexWidget 相关的任何内容,我认为它是将小部件添加为列表视图项的方法。 谢谢!

1
"index = new QModelIndex(model->index(0, 0));" <- 在堆上创建QModelIndex没有意义(QStringList同理)。同时将索引存储为成员变量是不好的,因为当返回到事件循环时,索引可能会变得无效。如果需要存储索引,请使用QPersistentModelIndex。 - Frank Osterfeld
你的 sizeHint() 必须是 const 才能覆盖基类的 sizeHint()const 并生效。另外,我指的是 ProfileItem::sizeHint(),而不是 View::sizeHint()。 - Frank Osterfeld
我为视图和ProfileItem实现了sizeHint(),但似乎没有改变什么。在cpp中,我使用了QSize ProfileItem::sizeHint() const { return QSize(300, 100); },在头文件中使用了QSize sizeHint() const; - Jacob Krieg
这是否可行?我倾向于认为这是不可能完成的 :( - Jacob Krieg
请在此处发布您的所有代码。您提供的代码链接现在无效,而您发布的Prefs.cpp与Profile.cpp相同。顺便说一句,我猜您完全违反了Qt中的MVC规则。为什么要将小部件用作列表项?它既不属于M也不属于V。如果您真的想自定义外观,我猜您应该在委托的paint()函数中进行。正如文档所说:“在Qt项目视图(例如QTableView)中显示模型数据时,委托绘制单个项目。” 您应该更经常地参考在线文档。 "http://qt-project.org/doc/qt-5.0/qtdoc/classes.html" - yeh
显示剩余2条评论
1个回答

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接