问题
I tried to use the cities-standarditem of the Qt exemple and adapt it to my exemple. I have a strange result:
Here is my User 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;
};
and i have declared a usermodel.h:
class UserModel: public QStandardItemModel
{
Q_OBJECT
public:
UserModel(QList<User> users, QObject *parent = Q_NULLPTR);
QHash<int, QByteArray> roleNames() const;
};
And here is the implementations of the constructor and the roleNames functions:
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;
}
My table view only show the last Role added with the function:
item->setData(user.getFirstname(), FirstnameRole);
If its the age lastly added, its the age showed... Any clues ?
回答1:
Let's say you really need a custom model and want to extend an existing one. Since your data is in tabular fashion, I'd suggest to use QAbstractTableModel
as the base class.
So let's have this class:
class UserModel: public QAbstractTableModel
{
Q_OBJECT
QList<User> _users;
public:
UserModel(QList<User> users, QObject *parent = Q_NULLPTR) : QAbstractTableModel(parent), _users(users){}
As you can see, the class itself stores a list of users, given at construction time. The constructor itself does nothing but copy-initializing the list.
Then you need to supply these implementation, at least:
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 {};
}
While columnCount
is constant and always returns 3, rowCount
will return the number of items in the list of users.
In data
implementation, the index passed is inspected and a value is returned, according to the index row and column, and the passed role.
It's important to understand that when the view calls data
passing a role
equal to Qt::DisplayRole
, the function should return the very data that will be shown in the cell at (index.row(), index.column())
, in our case: one of the three User
's data members.
It's quite useful to reimplement the sort
function as well, i.e.
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());
}
}
This way you let the user sort by column, as expected:
myTableView->setModel(new UserModel(list));
myTableView->model()->sort(2, Qt::DescendingOrder); //sort by first age, in descending order
If, for some reason, you want to use custom roles, please have your enum be like this:
enum ItemRoles {
FirstnameRole = Qt::UserRole,
LastnameRole,
AgeRole,
};
Starting from Qt::UserRole
(which is there for this very purpose) ensures that your roles don't clash whit builtin roles.
Please notice that the above code is meant to suggest a possible solution and it's not the solution itself (and lacks many important features like bounds checking and memory management).
来源:https://stackoverflow.com/questions/59369248/qstandarditemmodel-binding-to-custom-object