【问题标题】:QStandardItemModel & binding to custom objectQStandardItemModel & 绑定到自定义对象
【发布时间】:2019-12-17 07:14:33
【问题描述】:

我尝试使用 Qt 示例的城市标准项并将其调整为我的示例。我有一个奇怪的结果:

这是我的用户类:

class User{
public:
User();

QString getFirstname() const;
void setFirstname(const QString &value);

QString getLastname() const;
void setLastname(const QString &value);

int getAge() const;
void setAge(int value);

private:
QString firstname;
QString lastname;
int age;
};

我已经声明了一个 usermodel.h:

class UserModel: public QStandardItemModel
{
    Q_OBJECT
public:
    UserModel(QList<User> users, QObject *parent = Q_NULLPTR);

    QHash<int, QByteArray> roleNames() const;
};

这里是构造函数和 roleNames 函数的实现:

enum ItemRoles {
    FirstnameRole,
    LastnameRole,
    AgeRole,
};


UserModel::UserModel(QList<User> users, QObject *parent) : QStandardItemModel(parent)
{    

    //this->setItemRoleNames(roleNames());
    this->setColumnCount(3);
    for (auto user: users) {
        QStandardItem *item = new QStandardItem();
        item->setData(user.getFirstname(), FirstnameRole);
        item->setData(user.getLastname(), LastnameRole);
        item->setData(user.getAge(), AgeRole);
        appendRow(item);
    }

    setSortRole(FirstnameRole);
}


QHash<int, QByteArray> UserModel::roleNames() const
{
    QHash<int, QByteArray> mapping = QStandardItemModel::roleNames();

    mapping[FirstnameRole] = "firstname";
    mapping[LastnameRole] = "lastname";
    mapping[AgeRole] = "age";

    return mapping;
}

我的表格视图仅显示使用该功能添加的最后一个角色: item-&gt;setData(user.getFirstname(), FirstnameRole);

如果是最后添加的年龄,则显示的年龄... 有什么线索吗?

【问题讨论】:

    标签: c++ qt qstandarditemmodel qstandarditem


    【解决方案1】:

    假设您真的需要一个自定义模型并希望扩展现有模型。由于您的数据采用表格形式,我建议使用 QAbstractTableModel 作为基类。

    那么让我们来上课吧:

    class UserModel: public QAbstractTableModel
    {
        Q_OBJECT
        QList<User> _users;
    public:
        UserModel(QList<User> users, QObject *parent = Q_NULLPTR) : QAbstractTableModel(parent), _users(users){}
    

    如您所见,该类本身存储了一个用户列表,在构建时给出。构造函数本身只对列表进行复制初始化。

    那么你至少需要提供这些实现:

    int rowCount(const QModelIndex &) const override
    {
        return _users.size();
    }
    int columnCount(const QModelIndex &) const override
    {
        return 3;
    }
    QVariant data(const QModelIndex &index, int role) const override
    {
        if(role == Qt::DisplayRole)
        {
            User user = _users.at(index.row());
            QVariant data[] = { user.getFirstname(), user.getLastname() , user.getAge() };
            return data[index.column()];
        }
        return {};
    }
    

    虽然columnCount 是常量并且始终返回3,但rowCount 将返回用户列表中的项目数。 在data 实现中,根据索引rowcolumn,以及传递的role,检查传递的索引并返回一个值. 重要的是要理解,当视图调用data 传递一个等于Qt::DisplayRolerole 时,该函数应该返回将在单元格中显示的数据(index.row(), index.column()),在我们的例子中:三个之一User 的数据成员。

    重新实现sort函数也非常有用,即

    void sort(int column, Qt::SortOrder order) override
    {
        auto fnSort = [](const User & u1, const User & u2){ return u1.getFirstname() < u2.getFirstname(); };
        auto lnSort = [](const User & u1, const User & u2){ return u1.getLastname() < u2.getLastname(); };
        auto agSort = [](const User & u1, const User & u2){ return u1.getAge() < u2.getAge(); };
    
        std::function<bool (const User &, const User &)>  sortFn[] = {fnSort, lnSort, agSort};
        std::sort(_users.begin(), _users.end(), sortFn[column]);
    
        if(order == Qt::DescendingOrder)
        {
            std::reverse(_users.begin(), _users.end());
        }
    }
    

    这样你就可以让用户按列排序,正如预期的那样:

    myTableView->setModel(new UserModel(list));
    myTableView->model()->sort(2, Qt::DescendingOrder); //sort by first age, in descending order
    

    如果出于某种原因,您想使用 自定义 角色,请让您的枚举如下所示:

    enum ItemRoles {
        FirstnameRole = Qt::UserRole,
        LastnameRole,
        AgeRole,
    };
    

    Qt::UserRole 开始(就是为了这个目的)确保您的角色不会与内置角色发生冲突。

    请注意,上面的代码旨在建议一个可能的解决方案,而不是解决方案本身(并且缺少许多重要的功能,如边界检查和内存管理)。

    【讨论】:

    • 非常感谢您,为什么 QAbstractTableModel 而不是 QStandardItemModel ?我的尝试有什么问题?并且...您能用内存 mngt 解释问题吗?谢谢你!
    • 我真的不明白如何在模型设置后添加单个用户。你能帮帮我吗?插入行?无法完成这项工作:(
    • @user3178486 早上好。请不要在 cmets 中提问,只需发布​​新问题,以便不仅是我,而且 很多 其他用户都能够看到它们并帮助您。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多