QML TreeView 的 C++ 模型
C++ model for QML TreeView
由于缺少任何其他 Qt 演示,我正在使用 Qt 小部件的 SimpleTreeModel
演示来为我的 QML TreeView 实现 C++ 模型。我已经定义了角色,因此 QML 可以使用它,但我无法将它们与实际模型数据连接起来。
我还发现有趣的是小部件 (C++) 演示工作正常,但 TreeModel
似乎没有将数据存储为其成员变量..让我摸不着头脑。 我想通了,每个 TreeItem 都存储它的所有子项,而 TreeModel 只有一个 rootItem
,它又将所有数据存储为它的子项。
树项class
class TreeItem
{
public:
explicit TreeItem(const QList<QVariant> &data, TreeItem *parentItem = 0);
~TreeItem();
void appendChild(TreeItem *child);
TreeItem *child(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
int row() const;
TreeItem *parentItem();
private:
QList<TreeItem*> m_childItems;
QList<QVariant> m_itemData;
TreeItem *m_parentItem;
};
树模型class
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum DisplayRoles {
TitleRole = Qt::UserRole + 1,
SummaryRole
};
explicit TreeModel(const QString &data, QObject *parent = 0);
~TreeModel();
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QHash<int, QByteArray> TreeModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[TitleRole] = "title";
roles[SummaryRole] = "summary";
return roles;
}
private:
void setupModelData(const QStringList &lines, TreeItem *parent);
TreeItem *rootItem;
};
模型从 default.txt
加载数据
TreeModel::TreeModel(const QString &data, QObject *parent)
: QAbstractItemModel(parent)
{
QList<QVariant> rootData;
rootData << "Title" << "Summary";
rootItem = new TreeItem(rootData);
setupModelData(data.split(QString("\n")), rootItem);
}
void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
{
QList<TreeItem*> parents;
QList<int> indentations;
parents << parent;
indentations << 0;
int number = 0;
while (number < lines.count()) {
int position = 0;
while (position < lines[number].length()) {
if (lines[number].mid(position, 1) != " ")
break;
position++;
}
QString lineData = lines[number].mid(position).trimmed();
if (!lineData.isEmpty()) {
// Read the column data from the rest of the line.
QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts);
QList<QVariant> columnData;
for (int column = 0; column < columnStrings.count(); ++column)
columnData << columnStrings[column];
if (position > indentations.last()) {
// The last child of the current parent is now the new parent
// unless the current parent has no children.
if (parents.last()->childCount() > 0) {
parents << parents.last()->child(parents.last()->childCount()-1);
indentations << position;
}
} else {
while (position < indentations.last() && parents.count() > 0) {
parents.pop_back();
indentations.pop_back();
}
}
// Append a new item to the current parent's list of children.
parents.last()->appendChild(new TreeItem(columnData, parents.last()));
}
++number;
}
}
我的问题出在这个函数中,我如何将角色与存储在 rootItem
中的数据联系起来?。注意 titleString
和 summaryString
是可能的建议功能(如果需要),但我不知道在其中写什么才能访问数据!
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.isValid() && role >= TitleRole) {
switch (role) {
case TitleRole:
return QVariant(titleString(rootItem(index))); // get title through rootItem?
case SummaryRole:
return QVariant(summaryString(rootItem(index))); // get summary through rootItem?
}
}
if (role != Qt::DisplayRole)
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->data(index.column());
}
default.txt
具有以下数据,但 Qt Creator 演示本身也提供了相同的数据。
Getting Started How to familiarize yourself with Qt Designer
Launching Designer Running the Qt Designer application
The User Interface How to interact with Qt Designer
Designing a Component Creating a GUI for your application
Creating a Dialog How to create a dialog
Composing the Dialog Putting widgets into the dialog example
Creating a Layout Arranging widgets on a form
Signal and Slot Connections Making widget communicate with each other
Using a Component in Your Application Generating code from forms
The Direct Approach Using a form without any adjustments
The Single Inheritance Approach Subclassing a form's base class
The Multiple Inheritance Approach Subclassing the form itself
Automatic Connections Connecting widgets using a naming scheme
A Dialog Without Auto-Connect How to connect widgets without a naming scheme
A Dialog With Auto-Connect Using automatic connections
Form Editing Mode How to edit a form in Qt Designer
Managing Forms Loading and saving forms
Editing a Form Basic editing techniques
The Property Editor Changing widget properties
The Object Inspector Examining the hierarchy of objects on a form
Layouts Objects that arrange widgets on a form
Applying and Breaking Layouts Managing widgets in layouts
Horizontal and Vertical Layouts Standard row and column layouts
The Grid Layout Arranging widgets in a matrix
Previewing Forms Checking that the design works
Using Containers How to group widgets together
General Features Common container features
Frames QFrame
Group Boxes QGroupBox
Stacked Widgets QStackedWidget
Tab Widgets QTabWidget
Toolbox Widgets QToolBox
Connection Editing Mode Connecting widgets together with signals and slots
Connecting Objects Making connections in Qt Designer
Editing Connections Changing existing connections
除了没有文本外,我的输出显示的行数与小部件演示中的行数相同。它似乎只是没有正确连接到角色,或者角色没有连接到一天。我附上了输出的屏幕截图。
所以如果有人试图做同样的事情,我想通了,这就是答案。模型的数据方法应该是下面这样。
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if (index.isValid() && role >= TitleRole) {
switch (role) {
case TitleRole:
return item->data(0);
case SummaryRole:
return item->data(1);
}
}
if (role != Qt::DisplayRole)
return QVariant();
return item->data(index.column());
}
TreeItem
可以在实际应用程序中更改以存储特定数据,在这种情况下,上述方法将指向该数据而不是列号方法。
由于缺少任何其他 Qt 演示,我正在使用 Qt 小部件的 SimpleTreeModel
演示来为我的 QML TreeView 实现 C++ 模型。我已经定义了角色,因此 QML 可以使用它,但我无法将它们与实际模型数据连接起来。
我还发现有趣的是小部件 (C++) 演示工作正常,但 我想通了,每个 TreeItem 都存储它的所有子项,而 TreeModel 只有一个 TreeModel
似乎没有将数据存储为其成员变量..让我摸不着头脑。 rootItem
,它又将所有数据存储为它的子项。
树项class
class TreeItem
{
public:
explicit TreeItem(const QList<QVariant> &data, TreeItem *parentItem = 0);
~TreeItem();
void appendChild(TreeItem *child);
TreeItem *child(int row);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
int row() const;
TreeItem *parentItem();
private:
QList<TreeItem*> m_childItems;
QList<QVariant> m_itemData;
TreeItem *m_parentItem;
};
树模型class
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum DisplayRoles {
TitleRole = Qt::UserRole + 1,
SummaryRole
};
explicit TreeModel(const QString &data, QObject *parent = 0);
~TreeModel();
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE;
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QHash<int, QByteArray> TreeModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[TitleRole] = "title";
roles[SummaryRole] = "summary";
return roles;
}
private:
void setupModelData(const QStringList &lines, TreeItem *parent);
TreeItem *rootItem;
};
模型从 default.txt
TreeModel::TreeModel(const QString &data, QObject *parent)
: QAbstractItemModel(parent)
{
QList<QVariant> rootData;
rootData << "Title" << "Summary";
rootItem = new TreeItem(rootData);
setupModelData(data.split(QString("\n")), rootItem);
}
void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent)
{
QList<TreeItem*> parents;
QList<int> indentations;
parents << parent;
indentations << 0;
int number = 0;
while (number < lines.count()) {
int position = 0;
while (position < lines[number].length()) {
if (lines[number].mid(position, 1) != " ")
break;
position++;
}
QString lineData = lines[number].mid(position).trimmed();
if (!lineData.isEmpty()) {
// Read the column data from the rest of the line.
QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts);
QList<QVariant> columnData;
for (int column = 0; column < columnStrings.count(); ++column)
columnData << columnStrings[column];
if (position > indentations.last()) {
// The last child of the current parent is now the new parent
// unless the current parent has no children.
if (parents.last()->childCount() > 0) {
parents << parents.last()->child(parents.last()->childCount()-1);
indentations << position;
}
} else {
while (position < indentations.last() && parents.count() > 0) {
parents.pop_back();
indentations.pop_back();
}
}
// Append a new item to the current parent's list of children.
parents.last()->appendChild(new TreeItem(columnData, parents.last()));
}
++number;
}
}
我的问题出在这个函数中,我如何将角色与存储在 rootItem
中的数据联系起来?。注意 titleString
和 summaryString
是可能的建议功能(如果需要),但我不知道在其中写什么才能访问数据!
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.isValid() && role >= TitleRole) {
switch (role) {
case TitleRole:
return QVariant(titleString(rootItem(index))); // get title through rootItem?
case SummaryRole:
return QVariant(summaryString(rootItem(index))); // get summary through rootItem?
}
}
if (role != Qt::DisplayRole)
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->data(index.column());
}
default.txt
具有以下数据,但 Qt Creator 演示本身也提供了相同的数据。
Getting Started How to familiarize yourself with Qt Designer
Launching Designer Running the Qt Designer application
The User Interface How to interact with Qt Designer
Designing a Component Creating a GUI for your application
Creating a Dialog How to create a dialog
Composing the Dialog Putting widgets into the dialog example
Creating a Layout Arranging widgets on a form
Signal and Slot Connections Making widget communicate with each other
Using a Component in Your Application Generating code from forms
The Direct Approach Using a form without any adjustments
The Single Inheritance Approach Subclassing a form's base class
The Multiple Inheritance Approach Subclassing the form itself
Automatic Connections Connecting widgets using a naming scheme
A Dialog Without Auto-Connect How to connect widgets without a naming scheme
A Dialog With Auto-Connect Using automatic connections
Form Editing Mode How to edit a form in Qt Designer
Managing Forms Loading and saving forms
Editing a Form Basic editing techniques
The Property Editor Changing widget properties
The Object Inspector Examining the hierarchy of objects on a form
Layouts Objects that arrange widgets on a form
Applying and Breaking Layouts Managing widgets in layouts
Horizontal and Vertical Layouts Standard row and column layouts
The Grid Layout Arranging widgets in a matrix
Previewing Forms Checking that the design works
Using Containers How to group widgets together
General Features Common container features
Frames QFrame
Group Boxes QGroupBox
Stacked Widgets QStackedWidget
Tab Widgets QTabWidget
Toolbox Widgets QToolBox
Connection Editing Mode Connecting widgets together with signals and slots
Connecting Objects Making connections in Qt Designer
Editing Connections Changing existing connections
除了没有文本外,我的输出显示的行数与小部件演示中的行数相同。它似乎只是没有正确连接到角色,或者角色没有连接到一天。我附上了输出的屏幕截图。
所以如果有人试图做同样的事情,我想通了,这就是答案。模型的数据方法应该是下面这样。
QVariant TreeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if (index.isValid() && role >= TitleRole) {
switch (role) {
case TitleRole:
return item->data(0);
case SummaryRole:
return item->data(1);
}
}
if (role != Qt::DisplayRole)
return QVariant();
return item->data(index.column());
}
TreeItem
可以在实际应用程序中更改以存储特定数据,在这种情况下,上述方法将指向该数据而不是列号方法。