QStandardItemModel & 绑定到自定义对象
QStandardItemModel & binding to custom object
我尝试使用 Qt 示例的 cities-standarditem 并使其适应我的示例。我有一个奇怪的结果:
这是我的用户 class:
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;
}
我的table视图只显示最后添加了功能的角色:
item->setData(user.getFirstname(), FirstnameRole);
如果是最后添加的年龄,就是显示的年龄...
有什么线索吗?
假设您确实需要一个自定义模型并且想要扩展现有模型。由于您的数据采用表格形式,我建议使用 QAbstractTableModel
作为基础 class。
所以让我们这样 class:
class UserModel: public QAbstractTableModel
{
Q_OBJECT
QList<User> _users;
public:
UserModel(QList<User> users, QObject *parent = Q_NULLPTR) : QAbstractTableModel(parent), _users(users){}
如您所见,class 本身存储了在构造时给定的用户列表。构造函数本身除了复制初始化列表外什么都不做。
那么你至少需要提供这些实现:
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
是常量并且总是 returns 3,但 rowCount
将 return 用户列表中的项目数。
在 data
实现中,根据索引 row 和 column[=54=,检查传递的索引并 returned 值],以及传递的角色。
重要的是要理解当视图调用 data
传递一个等于 Qt::DisplayRole
的 role
时,该函数应该 return 将显示在 [= 处的单元格中的数据22=],在我们的例子中:三个 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
开始(就是为了这个目的)确保您的角色不会与内置角色发生冲突。
请注意,以上代码旨在建议一个可能的解决方案,而不是解决方案本身(并且缺少许多重要功能比如边界检查和内存管理)。
我尝试使用 Qt 示例的 cities-standarditem 并使其适应我的示例。我有一个奇怪的结果:
这是我的用户 class:
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;
}
我的table视图只显示最后添加了功能的角色:
item->setData(user.getFirstname(), FirstnameRole);
如果是最后添加的年龄,就是显示的年龄... 有什么线索吗?
假设您确实需要一个自定义模型并且想要扩展现有模型。由于您的数据采用表格形式,我建议使用 QAbstractTableModel
作为基础 class。
所以让我们这样 class:
class UserModel: public QAbstractTableModel
{
Q_OBJECT
QList<User> _users;
public:
UserModel(QList<User> users, QObject *parent = Q_NULLPTR) : QAbstractTableModel(parent), _users(users){}
如您所见,class 本身存储了在构造时给定的用户列表。构造函数本身除了复制初始化列表外什么都不做。
那么你至少需要提供这些实现:
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
是常量并且总是 returns 3,但 rowCount
将 return 用户列表中的项目数。
在 data
实现中,根据索引 row 和 column[=54=,检查传递的索引并 returned 值],以及传递的角色。
重要的是要理解当视图调用 data
传递一个等于 Qt::DisplayRole
的 role
时,该函数应该 return 将显示在 [= 处的单元格中的数据22=],在我们的例子中:三个 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
开始(就是为了这个目的)确保您的角色不会与内置角色发生冲突。
请注意,以上代码旨在建议一个可能的解决方案,而不是解决方案本身(并且缺少许多重要功能比如边界检查和内存管理)。