QRangeModel Class
QRangeModel 为任何 C++ 范围实现QAbstractItemModel 。更多
头文件: | #include <QRangeModel> |
CMake: | find_package(Qt6 REQUIRED COMPONENTS Core) target_link_libraries(mytarget PRIVATE Qt6::Core) |
qmake: | QT += core |
自 | Qt 6.10 |
继承: | QAbstractItemModel |
注意:该类中的所有函数都是可重入的。
公共类型
(since 6.10) struct | RowOptions |
enum class | RowCategory { Default, MultiRoleItem } |
属性
- roleNames : QHash<int, QByteArray>
公共函数
QRangeModel(Range &&range, QObject *parent = nullptr) | |
QRangeModel(Range &&range, Protocol &&protocol, QObject *parent = nullptr) | |
virtual | ~QRangeModel() override |
void | resetRoleNames() |
void | setRoleNames(const QHash<int, QByteArray> &names) |
重新实现的公共函数
virtual QModelIndex | buddy(const QModelIndex &index) const override |
virtual bool | canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override |
virtual bool | canFetchMore(const QModelIndex &parent) const override |
virtual bool | clearItemData(const QModelIndex &index) override |
virtual int | columnCount(const QModelIndex &parent = {}) const override |
virtual QVariant | data(const QModelIndex &index, int role = Qt::DisplayRole) const override |
virtual bool | dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override |
virtual void | fetchMore(const QModelIndex &parent) override |
virtual Qt::ItemFlags | flags(const QModelIndex &index) const override |
virtual bool | hasChildren(const QModelIndex &parent = QModelIndex()) const override |
virtual QVariant | headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override |
virtual QModelIndex | index(int row, int column, const QModelIndex &parent = {}) const override |
virtual bool | insertColumns(int column, int count, const QModelIndex &parent = {}) override |
virtual bool | insertRows(int row, int count, const QModelIndex &parent = {}) override |
virtual QMap<int, QVariant> | itemData(const QModelIndex &index) const override |
virtual QModelIndexList | match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const override |
virtual QMimeData * | mimeData(const QModelIndexList &indexes) const override |
virtual QStringList | mimeTypes() const override |
virtual bool | moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationColumn) override |
virtual bool | moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationRow) override |
virtual void | multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const override |
virtual QModelIndex | parent(const QModelIndex &child) const override |
virtual bool | removeColumns(int column, int count, const QModelIndex &parent = {}) override |
virtual bool | removeRows(int row, int count, const QModelIndex &parent = {}) override |
virtual QHash<int, QByteArray> | roleNames() const override |
virtual int | rowCount(const QModelIndex &parent = {}) const override |
virtual bool | setData(const QModelIndex &index, const QVariant &data, int role = Qt::EditRole) override |
virtual bool | setHeaderData(int section, Qt::Orientation orientation, const QVariant &data, int role = Qt::EditRole) override |
virtual bool | setItemData(const QModelIndex &index, const QMap<int, QVariant> &data) override |
virtual QModelIndex | sibling(int row, int column, const QModelIndex &index) const override |
virtual void | sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override |
virtual QSize | span(const QModelIndex &index) const override |
virtual Qt::DropActions | supportedDragActions() const override |
virtual Qt::DropActions | supportedDropActions() const override |
信号
void | roleNamesChanged() |
重新实现的受保护函数
virtual bool | event(QEvent *event) override |
virtual bool | eventFilter(QObject *object, QEvent *event) override |
受保护插槽
virtual void | resetInternalData() override |
详细说明
QRangeModel 可以将任何顺序可迭代 C++ 类型中的数据提供给 Qt 的模型/视图框架。这使得在Qt Widgets 和Qt Quick 项目视图中显示现有数据结构变得容易,并允许应用程序的用户使用图形用户界面来操作数据。
要使用 QRangeModel,请使用 C++ range 将其实例化,并将其设置为一个或多个视图的模型:
std::array<int, 5> numbers = {1, 2, 3, 4, 5}; QRangeModel model(numbers); listView.setModel(&model);
构建模型
范围可以是任何实现了标准方法std::begin
和std::end
的 C++ 类型,并且返回的迭代器类型满足std::forward_iterator
。如果std::size
可用,且迭代器满足std::random_access_iterator
,某些模型操作会执行得更好。
范围必须在构建模型时提供;没有随后设置范围的 API,也没有从模型中检索范围的 API。范围可以通过值、引用包装器或指针提供。模型的构建方式决定了通过模型 API 进行的更改是否会修改原始数据。
当以值构建时,模型会复制范围,修改模型的QAbstractItemModel API(如setData() 或insertRows() )不会对原始范围产生影响。
QRangeModel model(numbers);
由于没有再次检索范围的 API,按值范围构建模型大多只适用于显示只读数据。可以使用模型发出的信号(如dataChanged() )来监控数据的变化。
要使对模型的修改影响到原始范围,可以通过指针
QRangeModel model(&numbers);
或通过引用包装器提供:
QRangeModel model(std::ref(numbers));
在这种情况下,修改模型的QAbstractItemModel API 也会修改范围。修改范围结构的方法,如insertRows() 或removeColumns() ,除了引用一个突变迭代器来设置或清除数据外,还使用标准的 C++ 容器 APIresize()
,insert()
,erase()
。
注意: 一旦构建了模型并将其传递给视图,就不能再直接修改模型操作的范围。模型上的视图不会被告知这些更改,而且结构更改很可能会破坏模型所维护的QPersistentModelIndex 的实例。
调用者必须确保范围的生命周期超过模型的生命周期。
使用智能指针可确保只有在所有客户都使用完范围后才删除范围。
auto shared_numbers = std::make_shared<std::vector<int>>(numbers); QRangeModel model(shared_numbers);
QRangeModel 支持共享指针和唯一指针。
只读或可变
对于作为常量对象的范围(对其访问总是产生常量值,或所需的容器 API 不可用),QRangeModel 实现了写访问 API,不做任何事情并返回false
。在使用std::array
的示例中,模型不能添加或删除行,因为 C++ 数组中的条目数是固定的。但是可以使用setData() 来更改值,而且用户可以在列表视图中触发对值的编辑。将数组设为常量后,值也变成只读。
const std::array<int, 5> numbers = {1, 2, 3, 4, 5};
如果元素类型是常量,值也是只读的,例如在
std::array<const int, 5> numbers = {1, 2, 3, 4, 5};
在上述使用std::vector
的示例中,模型可以添加或删除行,数据也可以更改。将 range 作为常量引用传递将使模型变成只读。
QRangeModel model(std::cref(numbers));
注意: 如果范围中的值是常量,那么也无法通过QAbstractItemModel API 删除或插入列和行。要实现更精细的控制,请执行the C++ tuple protocol 。
行和列
范围中的元素被解释为模型的行。根据这些行元素的类型,QRangeModel 会将范围显示为列表、表格或树。
如果行元素是简单的值,那么范围将以列表的形式表示。
QList<int> numbers = {1, 2, 3, 4, 5}; QRangeModel model(numbers); // columnCount() == 1 QListView listView; listView.setModel(&model);
如果行元素的类型是可迭代范围,如向量、列表或数组,那么范围将以表格的形式表示。
std::vector<std::vector<int>> gridOfNumbers = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}, }; QRangeModel model(&gridOfNumbers); // columnCount() == 5 QTableView tableView; tableView.setModel(&model);
如果行类型提供了标准 C++ 容器 APIresize()
,insert()
,erase()
,那么列可以通过insertColumns() 和removeColumns() 添加和删除。所有行必须具有相同数量的列。
作为行的结构体和小工具
如果行类型实现了the C++ tuple protocol ,那么范围就会被表示为具有固定列数的表格。
using TableRow = std::tuple<int, QString>; QList<TableRow> numberNames = { {1, "one"}, {2, "two"}, {3, "three"} }; QRangeModel model(&numberNames); // columnCount() == 2 QTableView tableView; tableView.setModel(&model);
为 C++ 类型实现元组协议的一个更简单、更灵活的替代方法是使用 Qt 的元对象系统来声明一个带有属性的类型。这可以是声明为gadget 的值类型,也可以是QObject 的子类。
class Book { Q_GADGET Q_PROPERTY(QString title READ title) Q_PROPERTY(QString author READ author) Q_PROPERTY(QString summary MEMBER m_summary) Q_PROPERTY(int rating READ rating WRITE setRating) public: Book(const QString &title, const QString &author); // C++ rule of 0: destructor, as well as copy/move operations // provided by the compiler. // read-only properties QString title() const { return m_title; } QString author() const { return m_author; } // read/writable property with input validation int rating() const { return m_rating; } void setRating(int rating) { m_rating = qBound(0, rating, 5); } private: QString m_title; QString m_author; QString m_summary; int m_rating = 0; };
使用QObject 子类可以使属性可绑定或具有更改通知信号。不过,为项目使用QObject 实例会产生大量内存开销。
使用 Qt 小工具或对象比执行元组协议更方便、更灵活。这些类型也可在 QML 中直接访问。不过,通过属性系统访问会带来一些运行时开销。对于性能关键的模型,可考虑实施元组协议,以便在编译时生成访问代码。
多角色项
data()、setData()、clearItemData()等实现所操作的项的类型在整个模型中可以是相同的--如上面的gridOfNumbers
示例。但范围也可以为不同列设置不同的项类型,如numberNames
的例子。
默认情况下,该值用于Qt::DisplayRole 和Qt::EditRole 角色。大多数视图都希望该值是convertible to and from a QString (但自定义委托可能会提供更大的灵活性)。
具有多个角色的关联容器
如果项目是一个关联容器,使用int
、Qt::ItemDataRole 或QString 作为键类型,并使用QVariant 作为映射类型,那么 QRangeModel 会将该容器解释为存储多个角色的数据。data() 和setData() 函数会返回并修改容器中的映射值,而setItemData() 会修改所有提供的值,itemData() 会返回所有存储的值,而clearItemData() 会清除整个容器。
using ColorEntry = QMap<Qt::ItemDataRole, QVariant>; const QStringList colorNames = QColor::colorNames(); QList<ColorEntry> colors; colors.reserve(colorNames.size()); for (const QString &name : colorNames) { const QColor color = QColor::fromString(name); colors << ColorEntry{{Qt::DisplayRole, name}, {Qt::DecorationRole, color}, {Qt::ToolTipRole, color.name()}}; } QRangeModel colorModel(colors); QListView list; list.setModel(&colorModel);
用作键的最有效数据类型是Qt::ItemDataRole 或int
。使用int
时,itemData() 会按原样返回容器,而不必创建数据副本。
作为多角色项目的小工具和对象
小工具和QObject 类型也可以表示为多角色项。这些项目的属性将用于与name of a role 匹配的角色。如果所有项目都持有相同类型的小工具或QObject ,那么 QRangeModel 中的roleNames() 实现将返回该类型的属性列表。
class ColorEntry { Q_GADGET Q_PROPERTY(QString display MEMBER m_colorName) Q_PROPERTY(QColor decoration READ decoration) Q_PROPERTY(QString toolTip READ toolTip) public: ColorEntry(const QString &color = {}) : m_colorName(color) {} QColor decoration() const { return QColor::fromString(m_colorName); } QString toolTip() const { return QColor::fromString(m_colorName).name(); } private: QString m_colorName; };
在表格中使用时,这是小工具的默认表示方法:
QList<QList<ColorEntry>> colorTable; // ... QRangeModel colorModel(colorTable); QTableView table; table.setModel(&colorModel);
但在列表中使用时,这些类型默认表示为多列行,每个属性表示为单独的一列。要强制将小工具表示为列表中的多角色项,可通过特化 QRoleModel::RowOptions 将小工具声明为多角色类型,并将static constexpr auto rowCategory
成员变量设置为MultiRoleItem 。
class ColorEntry { Q_GADGET Q_PROPERTY(QString display MEMBER m_colorName) Q_PROPERTY(QColor decoration READ decoration) Q_PROPERTY(QString toolTip READ toolTip) public: ... }; template <> struct QRangeModel::RowOptions<ColorEntry> { static constexpr auto rowCategory = QRangeModel::RowCategory::MultiRoleItem; };
您还可以将此类类型包装成单元素元组,从而将列表变成一个只有一列的表格:
const QStringList colorNames = QColor::colorNames(); QList<std::tuple<ColorEntry>> colors; // ... QRangeModel colorModel(colors); QListView list; list.setModel(&colorModel);
在这种情况下,需要注意的是,直接访问列表数据中的元素需要使用std::get
:
ColorEntry firstEntry = std::get<0>(colors.at(0));
或结构化绑定:
auto [firstEntry] = colors.at(0);
行作为值或指针
在迄今为止的示例中,我们一直将 QRangeModel 用于持有值的范围。QRangeModel 也可以对持有指针(包括智能指针)的范围进行操作。这允许 QRangeModel 对多态类型的范围进行操作,如QObject 子类。
class Entry : public QObject { Q_OBJECT Q_PROPERTY(QString display READ display WRITE setDisplay NOTIFY displayChanged) Q_PROPERTY(QIcon decoration READ decoration WRITE setDecoration NOTIFY decorationChanged) Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY toolTipChanged) public: Entry() = default; QString display() const { return m_display; } void setDisplay(const QString &display) { if (m_display == display) return; m_display = display; emit displayChanged(m_display); } signals: void displayChanged(const QString &); ... }; std::vector<std::shared_ptr<Entry>> entries = { ... }; QRangeModel model(std::ref(entries)); QListView listView; listView.setModel(&model);
与值一样,行的类型定义了范围是以列表、表格还是树的形式表示。作为 QObjects 的行将以列的形式显示每个属性,除非QRangeModel::RowOptions 模板专门将类型声明为多角色项。
template <> struct QRangeModel::RowOptions<Entry> { static constexpr auto rowCategory = QRangeModel::RowCategory::MultiRoleItem; }; std::vector<std::shared_ptr<Entry>> entries = { std::make_shared<Entry>(), ... }; QRangeModel model(std::ref(entries));
注意: 如果范围持有原始指针,则必须从范围的指针或引用包装器构造 QRangeModel。否则,数据的所有权就会变得模糊不清,而且范围的副本仍会对相同的实际行数据进行操作,从而产生意想不到的副作用。
子类化 QRangeModel
通过对 QRangeModel 进行子类化,可以添加方便的应用程序接口,将范围的数据类型和结构考虑在内。
class NumbersModel : public QRangeModel { std::vector<int> m_numbers; public: NumbersModel(const std::vector<int> &numbers) : QRangeModel(std::ref(m_numbers)) , m_numbers(numbers) { }
这样做时,将范围添加为私有成员,并用引用包装器或指向该成员的指针调用 QRangeModel 构造函数。这样可以正确封装数据,避免直接访问。
void setNumber(int idx, int number) { setData(index(idx, 0), QVariant::fromValue(number)); } int number(int idx) const { return m_numbers.at(idx); } };
添加成员函数,提供对数据的类型安全访问,使用QAbstractItemModel API 执行修改范围的任何操作。只读访问可直接对数据结构进行操作。
数据树
QRangeModel 可以将数据结构表示为树形模型。这种树形数据结构需要同构:在树的所有层次上,子行列表需要使用与树本身完全相同的表示法。此外,行类型需要具有静态大小:要么是小工具或QObject 类型,要么是实现 {C++元组协议}的类型。
要将此类数据表示为树状,QRangeModel 必须能够遍历数据结构:对于任何给定的行,模型必须能够检索父行和可选的子行跨度。这些遍历功能可以通过行类型隐式提供,也可以通过显式协议类型提供。
隐式树遍历协议
class TreeRow; using Tree = std::vector<TreeRow>;
树本身是TreeRow
值的向量。关于行是使用值还是项的指针,请参见Tree Rows as pointers or values 。
class TreeRow { Q_GADGET // properties TreeRow *m_parent; std::optional<Tree> m_children; public: TreeRow() = default; // rule of 0: copy, move, and destructor implicitly defaulted
行类可以是上述任何固定大小的类型:实现元组协议的类型、小工具或QObject 。在本例中,我们使用小工具。
每个行项都需要维护一个指向父行的指针,以及一个可选的子行范围。该范围必须与树本身使用的范围结构相同。
使行类型默认为可构造是可选的,它允许模型构造新的行数据元素,例如在insertRow() 或moveRows() 实现中。
// tree traversal protocol implementation const TreeRow *parentRow() const { return m_parent; } const std::optional<Tree> &childRows() const { return m_children; }
树遍历协议可以作为行数据类型的成员函数来实现。constparentRow()
函数必须返回一个指向const行项的指针;而childRows()
函数必须返回一个指向conststd::optional
的引用,该引用可以容纳可选的子范围。
这两个函数足以让模型将树作为只读数据结构进行导航。为了让用户能够编辑视图中的数据,并让模型能够实现诸如insertRows(),removeRows() 和moveRows() 等可变模型 API,我们必须实现额外的写访问函数:
void setParentRow(TreeRow *parent) { m_parent = parent; } std::optional<Tree> &childRows() { return m_children; }
模型调用setParentRow()
函数和可变型childRows()
重载,将行移动或插入到现有的树分支中,并在旧值失效时更新父指针。childRows()
的非const 重载还提供了对行数据的写访问。
注: 该模型将设置行的父节点、从旧父节点移除该行以及将该行添加到新父节点的子节点列表作为单独的步骤来执行。这样可以保持较小的协议接口。
... // Helper to assembly a tree of rows, not used by QRangeModel template <typename ...Args> TreeRow &addChild(Args &&...args) { if (!m_children) m_children.emplace(Tree{}); auto &child = m_children->emplace_back(std::forward<Args>(args)...); child.m_parent = this; return child; } };
该类的其他实现与模型无关,但addChild()
辅助器为我们提供了一种构建树初始状态的便捷方法。
Tree tree = { {"..."}, {"..."}, {"..."}, }; // each toplevel row has three children tree[0].addChild("..."); tree[0].addChild("..."); tree[0].addChild("..."); tree[1].addChild("..."); tree[1].addChild("..."); tree[1].addChild("..."); tree[2].addChild("..."); tree[2].addChild("..."); tree[2].addChild("...");
用这样一个 range 的实例实例化的 QRangeModel 将以树的形式表示数据。
// instantiate the model with a pointer to the tree, not a copy! QRangeModel model(&tree); QTreeView view; view.setModel(&model);
树遍历协议在一个单独的类中
树遍历协议也可以在一个单独的类中实现。
struct TreeTraversal { TreeRow newRow() const { return TreeRow{}; } const TreeRow *parentRow(const TreeRow &row) const { return row.m_parent; } void setParentRow(TreeRow &row, TreeRow *parent) const { row.m_parent = parent; } const std::optional<Tree> &childRows(const TreeRow &row) const { return row.m_children; } std::optional<Tree> &childRows(TreeRow &row) const { return row.m_children; } };
将该协议实现的实例传递给 QRangeModel 构造函数:
QRangeModel model(&tree, TreeTraversal{});
树行作为指针或值
数据范围的行类型可以是值,也可以是指针。在上面的代码中,我们将树行作为向量中的值使用,这样就避免了显式内存管理。然而,当需要重新分配存储空间或插入或删除元素时,作为连续内存块的矢量会使所有迭代器和引用失效。这将影响到父项的指针,也就是向量中父行的位置。确保父项(以及引用父项中的项的QPersistentModelIndex 实例)保持有效会产生大量性能开销。在修改范围时,QRangeModel 的实现必须假定对范围的所有引用都会失效。
或者,我们也可以使用行指针范围作为树类型:
struct TreeRow; using Tree = std::vector<TreeRow *>;
在这种情况下,我们必须使用操作符new
显式分配所有 TreeRow 实例,并实现析构函数以delete
子代向量中的所有项。
structTreeRow { Q_GADGETpublic: TreeRow(constQString&value ={}) : m_value(value) {}~TreeRow() {if(m_children) qDeleteAll(*m_children); }// move-onlyTreeRow(TreeRow&&) = default; TreeRow&operator=(TreeRow&&) = default;// helper to populate template <typename ...args>TreeRow*addChild(Args&&. ..args) {if(!m_children) m_children.emplace(Tree{});auto *child = m_children->emplace_back(newTreeRow(std::forward<Args>(args)...)); child->m_parent = this;returnchild; }private:friend structTreeTraversal; QStringm_value; std::optional<Tree>m_children; TreeRow*m_parent =nullptr; }; Tree tree={newTreeRow("1"), newTreeRow("2"), newTreeRow("3"), newTreeRow("4"),}; tree[0]->addChild("1.1"); tree[1]->addChild("2.1"); tree[2]->addChild("3.1")->addChild("3.1.1"); tree[3]->addChild("4.1");
在构建一个以树的形式表示这些数据的模型之前,我们还需要实现树遍历协议。
struct TreeTraversal { TreeRow *newRow() const { return new TreeRow; } void deleteRow(TreeRow *row) { delete row; } const TreeRow *parentRow(const TreeRow &row) const { return row.m_parent; } void setParentRow(TreeRow &row, TreeRow *parent) { row.m_parent = parent; } const std::optional<Tree> &childRows(const TreeRow &row) const { return row.m_children; } std::optional<Tree> &childRows(TreeRow &row) { return row.m_children; } };
针对可变指针树的显式协议实现必须提供两个额外的成员函数newRow()
和deleteRow(RowType *)
。
int main(int argc, char **argv) { QApplication app(argc, argv); Tree tree = make_tree_of_pointers(); QRangeModel model(std::move(tree), TreeTraversal{}); QTreeView treeView; treeView.setModel(&model); treeView.show(); return app.exec(); }
当在insertRows() 中创建新行和在removeRows() 中删除行时,模型将调用这两个函数。此外,如果模型拥有数据的所有权,那么它还会在销毁时删除所有顶层行。请注意,在这个示例中,我们将树移入了模型中,因此不必再对其执行任何操作。QRangeModel 是通过将带有行指针的树数据移入模型而构建的,它将拥有数据的所有权,并在其析构函数中删除行指针。
使用指针作为行会带来一些内存分配和管理开销。不过,即使在范围内移动或范围重新分配时,行项目的引用也会保持稳定。当使用insertRows(),removeRows() 或moveRows() 时,这可以大大降低修改模型结构的成本。
每种选择都有不同的性能和内存开销权衡。最佳选择取决于使用的具体情况和数据结构。
C++ 元组协议
如上文numberNames
示例所示,行类型可以是元组,实际上也可以是任何实现元组协议的类型。该协议是通过专门化std::tuple_size
和std::tuple_element
以及重载未限定的get
函数来实现的。请为您的自定义行类型执行此操作,以便 Qt 中的模型/视图框架可以使用现有的结构化数据。
struct Book { QString title; QString author; QString summary; int rating = 0; template <size_t I, typename T> requires ((I <= 3) && std::is_same_v<std::remove_cvref_t<T>, Book>) friend inline decltype(auto) get(T &&book) { if constexpr (I == 0) return std::as_const(book.title); else if constexpr (I == 1) return std::as_const(book.author); else if constexpr (I == 2) return std::forward_like<T>(book.summary); else if constexpr (I == 3) return std::forward_like<T>(book.rating); } }; namespace std { template <> struct tuple_size<Book> : std::integral_constant<size_t, 4> {}; template <size_t I> struct tuple_element<I, Book> { using type = decltype(get<I>(std::declval<Book>())); }; }
在上述实现中,Book
类型的title
和author
值以const
的形式返回,因此模型将这两列中的项目标记为只读。用户将无法触发编辑,而setData() 将什么也不做并返回 false。对于summary
和rating
,实现会返回与书相同的值类别,因此,当get
被调用时,如果它是对Book
的可变引用,那么它将返回相应变量的可变引用。该模型使用户和程序访问都可以编辑这些列。
注: 上述get
的实现需要 C++23。
另请参阅 模型/视图编程。
成员类型文档
enum class QRangeModel::RowCategory
该枚举描述了QRangeModel 应如何显示它所构建的范围中的元素。
常量 | 值 | 描述 |
---|---|---|
QRangeModel::RowCategory::Default | 0 | QRangeModel 决定如何显示行。 |
QRangeModel::RowCategory::MultiRoleItem | 1 | QRangeModel 将把带有元对象的项目显示为多角色项目,在一维范围中使用时也是如此。 |
请为您的类型专用RowOptions 模板,并添加一个包含该枚举值的公共成员变量static constexpr auto rowCategory
。
另请参阅 RowOptions 。
属性文档
roleNames : QHash<int, QByteArray>
该属性包含模型的角色名称。
如果范围内的所有列都是同一类型,并且该类型提供了一个元对象(即小工具或QObject 子类),那么该属性将保存该类型的属性名称,并映射到Qt::UserRole 及以上的Qt::ItemDataRole 值。此外,"modelData "角色提供了对小工具或QObject 实例的访问。
通过将此属性显式设置为非空映射,可覆盖此默认行为。将此属性设置为空映射,或使用 resetRoleNames() 恢复默认行为。
访问功能:
virtual QHash<int, QByteArray> | roleNames() const override |
void | setRoleNames(const QHash<int, QByteArray> &names) |
void | resetRoleNames() |
Notifier 信号:
void | roleNamesChanged() |
另请参阅 QAbstractItemModel::roleNames().
成员函数文档
[explicit]
template <typename Range, typename Protocol, int = true> QRangeModel::QRangeModel(Range &&range, Protocol &&protocol, QObject *parent = nullptr)
[explicit]
template <typename Range, int = true> QRangeModel::QRangeModel(Range &&range, QObject *parent = nullptr)
[explicit]
template <typename Range, int = true> QRangeModel::QRangeModel(Range &&range, QObject *parent = nullptr)
构造一个QRangeModel 实例,对range 中的数据进行操作。range 必须是一个有std::begin
和std::end
的顺序范围。如果提供了protocol ,那么模型将使用协议实现把范围表示为一棵树。模型实例将成为parent 的子节点。
range 可以是指针或引用包装器,在这种情况下,更改模型 API(如setData() 或insertRow() )将会修改引用范围实例中的数据。如果range 是一个值(或移动到了模型中),则会连接到模型发出的信号,以响应数据的变化。
QRangeModel 在构造range 时,将不会访问它。这使得向该构造函数传递指向尚未完全构造的范围对象的指针或引用是合法的,例如在subclassing QRangeModel 时。
如果range 被移动到模型中,那么范围及其中的所有数据都将在模型销毁时被销毁。
注意: 虽然模型不会以其他方式获得 range 对象的所有权,但一旦模型已构建并传递给视图,您就不能直接修改range 。这种修改将不会发出必要的信号,以保持模型用户(其他模型或视图)与模型同步,从而导致不一致的结果、未定义的行为和崩溃。
[override virtual noexcept]
QRangeModel::~QRangeModel()
销毁QRangeModel 。
不会访问构建模型的范围,只有在模型是由移动范围构建的情况下才会销毁。
[override virtual]
QModelIndex QRangeModel::buddy(const QModelIndex &index) const
重实现:QAbstractItemModel::buddy(const QModelIndex &index) const.
[override virtual]
bool QRangeModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
重实现:QAbstractItemModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const.
[override virtual]
bool QRangeModel::canFetchMore(const QModelIndex &parent) const
重实现:QAbstractItemModel::canFetchMore(const QModelIndex &parent) const.
[override virtual]
bool QRangeModel::clearItemData(const QModelIndex &index)
重实现:QAbstractItemModel::clearItemData(const QModelIndex &index).
用默认构造值替换存储在index 的范围中的值。
对于在只读范围上操作的模型,或在实现the C++ tuple protocol 的行类型中的只读列上操作的模型,此实现会立即返回false
。
[override virtual]
int QRangeModel::columnCount(const QModelIndex &parent = {}) const
重实现:QAbstractItemModel::columnCount(const QModelIndex &parent) const.
返回模型的列数。对于所有parent 索引,此函数返回相同的值。
对于在静态大小的行类型上运行的模型,该返回值在模型的整个生命周期内始终是相同的。对于在动态大小的行类型上运行的模型,模型返回第一行的项数,如果模型没有行,则返回 0。
另请参阅 rowCount 和insertColumns()。
[override virtual]
QVariant QRangeModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const
重实现:QAbstractItemModel::data(const QModelIndex &index, int role) const.
返回给定role 下存储的数据,该数据为index 所指范围内的值。
如果该索引的项目类型是从int
、Qt::ItemDataRole 或QString 映射到QVariant 的关联容器,则会在该容器中查找并返回角色数据。
如果项目是一个小工具或QObject ,那么实现过程将返回与roleNames() 映射中的role 条目相匹配的项目属性值。
否则,该实现将通过QVariant::fromValue()
为Qt::DisplayRole
或Qt::EditRole
返回由该项目构建的QVariant 。对于其他角色,系统会返回一个无效的(默认构造的)QVariant 。
另请参阅 Qt::ItemDataRole 、setData() 和headerData()。
[override virtual]
bool QRangeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
重实现:QAbstractItemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent).
[override virtual protected]
bool QRangeModel::event(QEvent *event)
重实现:QObject::event(QEvent *e)。
[override virtual protected]
bool QRangeModel::eventFilter(QObject *object, QEvent *event)
重实现:QObject::eventFilter(QObject *watched, QEvent *event).
[override virtual]
void QRangeModel::fetchMore(const QModelIndex &parent)
重实现:QAbstractItemModel::fetchMore(const QModelIndex &parent).
[override virtual]
Qt::ItemFlags QRangeModel::flags(const QModelIndex &index) const
重实现:QAbstractItemModel::flags(const QModelIndex &index) const.
返回给定index 的项目标志。
该实现返回启用项目 (ItemIsEnabled
) 和允许选择项目 (ItemIsSelectable
) 的标志组合。对于在具有可变数据的范围上运行的模型,它还会设置允许项目可编辑的标志 (ItemIsEditable
)。
另请参阅 Qt::ItemFlags 。
[override virtual]
bool QRangeModel::hasChildren(const QModelIndex &parent = QModelIndex()) const
重实现:QAbstractItemModel::hasChildren(const QModelIndex &parent) const.
[override virtual]
QVariant QRangeModel::headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
重实现:QAbstractItemModel::headerData(int section, Qt::Orientation orientation, int role) const.
返回标题中给定的role 和section 的数据以及指定的orientation 。
对于水平标题,节号对应于列号。同样,对于垂直标题,节号与行号相对应。
对于水平页眉和Qt::DisplayRole role ,对使用数组作为行类型的范围进行操作的模型会返回section 。如果行类型是一个元组,那么实现会返回该类型的名称section 。对于小工具或QObject 类型的行,该函数会返回section 索引处的属性名称。
对于垂直标题,该函数总是返回QAbstractItemModel 中默认实现的结果。
另请参见 Qt::ItemDataRole,setHeaderData() 和QHeaderView 。
[override virtual]
QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent = {}) const
重实现:QAbstractItemModel::index(int row, int column, const QModelIndex &parent) const.
返回位于row 和column 的模型项在parent 中的索引。
对于在列表和表格范围内操作的模型,传递一个有效的父代会产生一个无效的索引。
另请参阅 parent().
[override virtual]
bool QRangeModel::insertColumns(int column, int count, const QModelIndex &parent = {})
重实现:QAbstractItemModel::insertColumns(int column, int count, const QModelIndex &parent).
在parent 所在范围的所有行中,在column 处的项目之前插入count 空列。如果成功,则返回true
;否则返回false
。
注意: 动态大小的行类型需要提供一个insert(const_iterator, size_t, value_type)
成员函数。
对于在只读范围或具有静态大小行类型(如元组、数组或结构体)的范围上运行的模型,此实现什么也不做,并立即返回false
。对于树模型,情况总是这样。
[override virtual]
bool QRangeModel::insertRows(int row, int count, const QModelIndex &parent = {})
重实现:QAbstractItemModel::insertRows(int row, int count, const QModelIndex &parent).
将count 在给定的row 之前的空行插入parent 的范围。如果成功,则返回true
;否则返回false
。
注意: 范围需要动态调整大小,并提供insert(const_iterator, size_t, value_type)
成员函数。
对于在只读或静态大小范围(如数组)上运行的模型,此实现什么也不做,并立即返回false
。
注意: 对于具有动态大小列类型的范围,列需要提供一个resize(size_t)
成员函数。
[override virtual]
QMap<int, QVariant> QRangeModel::itemData(const QModelIndex &index) const
重实现:QAbstractItemModel::itemData(const QModelIndex &index) const.
返回一个包含给定index 的项目在模型中所有预定义角色值的映射。
如果index 的项目类型是一个关联容器,从int
、Qt::ItemDataRole 或QString 映射到QVariant ,则返回该容器中的数据。
如果项目类型是小工具或QObject 子类,则会返回与role name 匹配的属性值。
如果项目不是关联容器、小工具或QObject 子类,则会调用基类实现。
另请参见 setItemData()、Qt::ItemDataRole 和data()。
[override virtual]
QModelIndexList QRangeModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const
重实现:QAbstractItemModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const.
[override virtual]
QMimeData *QRangeModel::mimeData(const QModelIndexList &indexes) const
重实现:QAbstractItemModel::mimeData(const QModelIndexList &indexes) const.
[override virtual]
QStringList QRangeModel::mimeTypes() const
重实现:QAbstractItemModel::mimeTypes() const.
[override virtual]
bool QRangeModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationColumn)
重实现:QAbstractItemModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild)。
将父sourceParent 下从给定的sourceColumn 开始的count 列移动到父destinationParent 下的destinationColumn 列。
如果列移动成功,则返回true
;否则返回false
。
[override virtual]
bool QRangeModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationRow)
重实现:QAbstractItemModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)。
将父代sourceParent 下从给定的sourceRow 开始的count 行移动到父代destinationParent 下的destinationRow 行。
如果行已成功移动,则返回true
;否则返回false
。
[override virtual]
void QRangeModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const
重实现:QAbstractItemModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDataSpan) const.
[override virtual]
QModelIndex QRangeModel::parent(const QModelIndex &child) const
重实现:QAbstractItemModel::parent(const QModelIndex &index) 常量。
返回child 索引处项的父项。
对于在列表和表格范围上操作的模型,此函数总是产生一个无效索引。对于在树上操作的模型,此函数返回由树遍历协议的 parent() 实现返回的行项的索引。
另请参阅 index() 和hasChildren()。
[override virtual]
bool QRangeModel::removeColumns(int column, int count, const QModelIndex &parent = {})
重实现:QAbstractItemModel::removeColumns(int column, int count, const QModelIndex &parent).
从column 处的项目中删除parent 处范围内所有行中的count 列。成功则返回true
,否则返回false
。
注意: 动态大小的行类型需要提供一个erase(const_iterator, size_t)
成员函数。
对于在只读范围或具有静态大小行类型(如元组、数组或结构体)的范围上运行的模型,此实现什么也不做,并立即返回false
。对于树模型,情况总是这样。
[override virtual]
bool QRangeModel::removeRows(int row, int count, const QModelIndex &parent = {})
重实现:QAbstractItemModel::removeRows(int row, int count, const QModelIndex &parent).
从给定的row 开始,删除parent 范围内的count 行。如果成功则返回true
,否则返回false
。
注意: 范围需要动态调整大小,并提供erase(const_iterator, size_t)
成员函数。
对于在只读或静态大小范围(如数组)上运行的模型,此实现什么也不做,并立即返回false
。
[override virtual protected slot]
void QRangeModel::resetInternalData()
重新实现:QAbstractItemModel::resetInternalData().
[override virtual]
QHash<int, QByteArray> QRangeModel::roleNames() const
重实现:QAbstractItemModel::roleNames() 常量。
注: 可以在QRangeModel 子类中重载此函数,但可能会破坏属性的行为。
注:roleNames 属性的获取函数。
另请参阅 setRoleNames().
[override virtual]
int QRangeModel::rowCount(const QModelIndex &parent = {}) const
重实现:QAbstractItemModel::rowCount(const QModelIndex &parent) const.
返回给定parent 下的行数。对于无效的parent 索引,这是根范围内的条目数。
如果parent 索引有效,那么对于在列表和表格范围上操作的模型,此函数总是返回 0。对于树,此函数返回树遍历协议的 childRows() 实现所返回的范围大小。
另请参阅 columnCount()、insertRows() 和hasChildren()。
[override virtual]
bool QRangeModel::setData(const QModelIndex &index, const QVariant &data, int role = Qt::EditRole)
重实现:QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role)。
将index 的项目的role 数据设置为data 。
如果index 的项目类型是一个关联容器,可从int
、Qt::ItemDataRole 或QString 映射到QVariant ,那么data 将存储在该容器中,键值由role 指定。
如果项目是一个小工具或QObject ,则data 会被写入与roleNames() 映射中的role 项匹配的项目属性中。如果找到一个属性,且data 存储了一个可转换为所需类型的值,则函数返回true
,否则返回false
。
否则,该实现会将data 中的值分配给Qt::DisplayRole
和Qt::EditRole
范围内index 的项,并返回true
。对于其他角色,该实现将返回false
。
对于在只读范围上操作的模型,或在实现the C++ tuple protocol 的行类型中的只读列上操作的模型,此实现会立即返回false
。
另请参阅 data() 。
[override virtual]
bool QRangeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &data, int role = Qt::EditRole)
重实现:QAbstractItemModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)。
另请参阅 headerData().
[override virtual]
bool QRangeModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &data)
重实现:QAbstractItemModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)。
如果index 的条目类型是一个关联容器,从int
或Qt::ItemDataRole 映射到QVariant ,那么data 中的条目就会存储在该容器中。如果关联容器从QString 映射到QVariant ,则只存储data 中的值,这些值在role names 表中有映射。
如果项目类型是小工具或QObject 子类,那么与role name 匹配的属性将被设置为data 中的相应值。
data 中没有条目的角色不会被修改。
对于可以复制的项目类型,该实现是事务性的,如果可以存储data 中的所有条目,则返回 true。如果有任何条目无法更新,则根本不会修改原始容器,函数返回 false。
如果条目不是关联容器、小工具或QObject 子类,则会调用基类实现,基类会为data 中的每个条目调用setData() 。
另请参阅 itemData(),setData() 和Qt::ItemDataRole 。
[override virtual]
QModelIndex QRangeModel::sibling(int row, int column, const QModelIndex &index) const
重实现:QAbstractItemModel::sibling(int row, int column, const QModelIndex &index) 常量。
返回位于index 的项目在row 和column 的同级项,如果该位置没有同级项,则返回无效的QModelIndex 。
这种实现方式比通过index 的parent() 要快得多。
另请参见 index()、QModelIndex::row() 和QModelIndex::column()。
[override virtual]
void QRangeModel::sort(int column, Qt::SortOrder order = Qt::AscendingOrder)
重实现:QAbstractItemModel::sort(int column, Qt::SortOrder order)。
[override virtual]
QSize QRangeModel::span(const QModelIndex &index) const
重实现:QAbstractItemModel::span(const QModelIndex &index) const.
[override virtual]
Qt::DropActions QRangeModel::supportedDragActions() const
重实现:QAbstractItemModel::supportedDragActions() const.
[override virtual]
Qt::DropActions QRangeModel::supportedDropActions() const
重实现:QAbstractItemModel::supportedDropActions() const.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.