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.11) struct | ItemAccess |
(since 6.10) struct | RowOptions |
(since 6.11) enum class | AutoConnectPolicy { None, Full, OnRead } |
(since 6.12) enum class | DropOperation { DontDrop, Automatic, OverwriteAndIgnore, OverwriteAndExtend, InsertAsSiblings, InsertAsChildren } |
| enum class | RowCategory { Default, MultiRoleItem } |
プロパティ
|
|
パブリック関数
| QRangeModel(Range &&range, QObject *parent = nullptr) | |
| QRangeModel(Range &&range, Protocol &&protocol, QObject *parent = nullptr) | |
| virtual | ~QRangeModel() override |
| QRangeModel::AutoConnectPolicy | autoConnectPolicy() const |
| void | resetRoleNames() |
| void | resetSortCollator() |
| void | resetSortRole() |
| void | resetSupportedDragActions() |
| void | resetSupportedDropActions() |
| void | setAutoConnectPolicy(QRangeModel::AutoConnectPolicy policy) |
| void | setRoleNames(const QHash<int, QByteArray> &names) |
| void | setSortCollator(const QCollator &collator) |
| void | setSortRole(int role) |
| void | setSupportedDragActions(Qt::DropActions actions) |
| void | setSupportedDropActions(Qt::DropActions actions) |
| QCollator | sortCollator() const |
| int | sortRole() const |
再実装されたパブリック関数
| 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 | autoConnectPolicyChanged(QRangeModel::AutoConnectPolicy policy) |
| void | roleNamesChanged() |
| void | sortCollatorChanged(const QCollator &collator) |
| void | sortRoleChanged(int role) |
| void | supportedDragActionsChanged(Qt::DropActions actions) |
| void | supportedDropActionsChanged(Qt::DropActions actions) |
再実装された保護関数
| 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++ の範囲を引数としてインスタンス化し、1 つ以上のビューのモデルとして設定します。
std::array<int, 5> numbers = {1, 2, 3, 4, 5};
QRangeModel model(numbers);
listView.setModel(&model);モデルの構築
範囲は、標準メソッド `std::begin ` および `std::end ` が実装されており、かつ返されるイテレータ型が `std::forward_iterator` を満たす任意の C++ 型であることができます。std::size が利用可能であり、かつイテレータが `std::random_access_iterator` を満たしている場合、特定のモデル操作のパフォーマンスが向上します。
モデルを構築する際には範囲を指定する必要があり、値、参照ラッパー、またはポインタで指定できます。モデルの構築方法によって、モデル API を通じた変更が元のデータを変更するかどうかが決まります。QRangeModelAdapter を使用すると、モデルを暗黙的に構築すると同時に、範囲としてモデルに直接的かつ型安全で便利なアクセスを行うことができます。
値で構築された場合、モデルは範囲のコピーを作成し、setData() やinsertRows() など、モデルを変更するQAbstractItemModel API は元の範囲に影響を与えません。
QRangeModel model(numbers);データに加えられた変更は、dataChanged() など、モデルから発信されるシグナルに接続することで監視できます。
モデルの変更を元の範囲に反映させるには、範囲をポインタで指定するか:
QRangeModel model(&numbers);または参照ラッパーを介して指定します:
QRangeModel model(std::ref(numbers));この場合、QAbstractItemModel モデルを変更する API は、範囲も変更します。insertRows() やremoveColumns() など、範囲の構造を変更するメソッドは、データを設定またはクリアするために変異型イテレータを間接参照することに加え、標準 C++ コンテナ APIresize() 、insert() 、erase() を使用します。
注: モデルが構築され、ビューに渡された後は 、モデルが操作する範囲を直接変更してはなりません。モデルに対するビューには変更が通知されず、構造的な変更により、モデルが保持するQPersistentModelIndex のインスタンスが破損する可能性があります。モデルを最新の状態に保ちつつ、基になる範囲と安全にやり取りするには、QRangeModelAdapter を使用してください。
呼び出し元は、範囲の存続期間がモデルの存続期間を上回ることを確認する必要があります。
スマートポインタを使用して、すべてのクライアントが範囲の使用を終了した時点で初めて範囲が削除されるようにしてください。
auto shared_numbers = std::make_shared<std::vector<int>>(numbers);
QRangeModel model(shared_numbers);QRangeModel は、共有ポインタと一意のポインタの両方をサポートしています。
読み取り専用または変更可能
const オブジェクトである範囲、アクセスによって常に定数値が返される範囲、または必要なコンテナ API が利用できない範囲の場合、QRangeModel は、何も実行せずに `false` を返す書き込みアクセス API を実装しています。std::array を使用する例では、C++ 配列のエントリ数は固定されているため、モデルは行の追加や削除を行うことはできません。 しかし、setData() を使用すれば値を変更することができ、ユーザーはリストビューで値の編集を実行できます。配列を const にすることで、値も読み取り専用になります。
const std::array<int, 5> numbers = {1, 2, 3, 4, 5};また、次の例のように、要素の型が const の場合も、値は読み取り専用になります。
std::array<const int, 5> numbers = {1, 2, 3, 4, 5};std::vector を使用した上記の例では、モデルで行の追加や削除が可能であり、データを変更することもできます。範囲を定数参照として渡すと、モデルは読み取り専用になります。
QRangeModel model(std::cref(numbers));注: 範囲内の値が constの場合 、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++ コンテナ API(resize() 、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++型に対してtupleプロトコルを実装するよりも、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 READ colorName)
Q_PROPERTY(QColor decoration READ decoration)
Q_PROPERTY(QString toolTip READ toolTip)
public:
ColorEntry(const QString &color = {})
: m_colorName(color)
{}
QString colorName() const
{
return m_colorName;
}
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 READ 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);値の場合と同様に、行の型によって、範囲がリスト、テーブル、またはツリーとして表現されるかが決まります。QObjectである行は、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 をサブクラス化することで、範囲のデータ型や構造を考慮した便利な API を追加することが可能になります。
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 型、あるいはthe C++ tuple protocol を実装する型です。
このようなデータをツリーとして表現するために、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() 関数は行項目へのポインタを返さなければならず、childRows() 関数は、オプションの子範囲を保持できる conststd::optional への参照を返さなければなりません。
これら2つの関数があれば、モデルがツリーを読み取り専用データ構造としてナビゲートするには十分です。ユーザーがビュー内のデータを編集できるようにし、モデルが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("...");そのような範囲のインスタンスを用いてインスタンス化された 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_GADGET
public:
TreeRow(constQString&value ={})
: m_value(value)
{}
~TreeRow()
{
if(m_children)
qDeleteAll(*m_children);
}
// 移動専用
TreeRow(TreeRow&&)= default;
TreeRow&operator=(TreeRow&&)= default;
// データ設定用のヘルパー関数
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;
QString m_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 *) の 2 つの追加のメンバ関数を提供する必要があります。
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() を使用する際、モデルの構造を変更する際のコストを大幅に削減できます。
それぞれの選択肢には、パフォーマンスとメモリオーバーヘッドのトレードオフが異なります。最適な選択肢は、具体的な使用ケースや使用されるデータ構造によって異なります。
テンプレートの特化によるカスタマイズ
QRangeModel は、デフォルトの挙動を上書きするために特化できる 2 つのネストされたテンプレート型を宣言しています。
前述したRowOptions テンプレートは、ヘッダーデータなど行型に固有の機能、あるいはデフォルトのフラグなど行内のすべての項目に一律に適用されるべき機能をカスタマイズするためのものです。一方、ItemAccess テンプレートは、ロールデータの読み取りや書き込みなど、項目型固有の挙動をカスタマイズするために使用されます。
これら2つのテンプレートは、常に基底型に対して特化させる必要があります。したがって、範囲にRow 型の行がstd::unique_ptr<Row> として格納されていたり、Item 型の項目がstd::shared_ptr<Item> として格納されていたりする場合でも、特化はRow およびItem に対して行う必要があります。
template <>
struct QRangeModel::ItemAccess<ColorEntry>
{
...
};
std::vector<std::shared_ptr<ColorEntry>> colors;
// ...
QRangeModel model(colors);注: C++では 、テンプレートの特化は、自身が所有する型に対してのみ行うべきであり、標準型や Qt 型に対しては行わないでください。制御できない型の挙動をカスタマイズする必要がある場合は、その型に対するサブクラスや集約型を作成してください。 なお、型エイリアスは独立した型ではないため、エイリアスタイプに対してテンプレートを特化させてはなりません。ただし、std::vector<MyGadget> など、自身が所有する型を用いて、標準またはQtのコンテナの特化を作成することは許可されています。
行および項目固有のフラグ
flags() のデフォルトの実装は、Qt::ItemIsSelectable 、Qt::ItemIsEnabled 、および(ツリーモデルの 0 列目の項目を除く)Qt::ItemNeverHasChildren の組み合わせを返します。Qt::ItemIsEditable およびQt::ItemIsDropEnabled フラグは、読み取り専用ではないモデルのすべての項目に対して設定され、Qt::ItemIsDragEnabled は、モデルが少なくとも 1 つのmime type をサポートしている限り設定されます。
行内のすべての項目のデフォルトの挙動をカスタマイズするには、RowOptions テンプレートを特化させます。項目ごとのフラグデータにアクセスするには、ItemAccess テンプレートを特化させます。両方を併用することも可能です。RowOptions では行内のすべての項目に共通するフラグを設定でき、ItemAccess では特定の型をバックエンドとする項目のフラグを設定できます。
ドラッグ&ドロップの処理
Qt 6.12以降、QRangeModelはflags()仮想関数を実装しており、モデルが少なくとも1つのmime type をサポートしている限り、モデル内のすべての有効なアイテムに対してQt::ItemIsDragEnabled フラグを設定します。QAbstractItemModel はQt内部の「application/x-qabstractitemmodeldatalist」MIMEタイプを提供するため、これがデフォルトの設定となります。 さらに、そのモデルが読み取り専用でない限り、そのようなモデル内の項目にはQt::ItemIsDropEnabled フラグが設定されます。これには無効なインデックスにある存在しない項目も含まれるため、ユーザーはビューの空いている領域にデータをドロップして、データを追加することができます。
追加のMIMEタイプへの対応は、QRangeModelをサブクラス化したり、それぞれの仮想関数をオーバーライドしたりすることなく実装できます。 QRangeModelは、ItemAccess およびRowOptions のカスタマイズテンプレート内の関数を検出して使用し、行やアイテムをmime data としてエンコードしたり、decode mime data して行やアイテムのシーケンスに変換したりします。これらのカスタマイズ関数は、QModelIndex やQVariant を経由することなく、行やアイテムの型に対して直接操作を行うことができます。
これにより、データのシリアライズを行うコードは型安全となり、データを格納するために使用される型の実装内に留めることができます。
さらに、supportedDragActions およびsupportedDropActions は、各QRangeModelインスタンスに対して設定可能なプロパティです。
C++の高度なトピック
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 として返されるため、モデルはこれら2つの列の項目を読み取り専用としてマークします。ユーザーは編集を開始できず、setData()は何も実行せずにfalseを返します。summary およびrating については、実装では書籍と同じ値カテゴリが返されるため、Book への可変参照を引数としてget が呼び出されると、対応する変数の可変参照が返されます。モデルは、ユーザーによる操作およびプログラムからのアクセス双方において、これらの列を編集可能にします。
注: 上記のget の実装には 、C++23が必要です。
バイナリ互換性に関する考慮事項
QRangeModelはテンプレートクラスではありません。ライブラリのAPIを通じてQRangeModelのインスタンスを(すべてのQObject クラスと同様に、ポインタまたは参照で)渡したり、ライブラリのパブリッククラスにQRangeModelを値として格納したりすることは安全です。
ただし、QRangeModel のコンストラクタはテンプレートであり、インライン化されており、モデルが操作する範囲の型に対して特化された内部実装がコンストラクタ内でインスタンス化されます。 ライブラリ API のインライン実装内でコンストラクタを呼び出してはなりません。これにより ODR 違反が発生し、そのライブラリがビルドされた Qt バージョンと、そのライブラリを使用するアプリケーションがビルドされた Qt バージョンが異なる場合、そのライブラリのバイナリ互換性が損なわれる可能性があります。
また、QRangeModel が、その実装が古いバージョンの Qt に対してコンパイルされたものであると検出した場合、Qt の新しいバージョンで導入された仮想関数の新しい実装や最適化された実装が使用されない可能性があります。 たとえば、sort() およびmatch() の実装は Qt 6.12 で新たに追加されましたが、使用されている Qt ライブラリが Qt 6.12 であっても、Qt 6.11 に対してコンパイルされたアプリケーションからは呼び出されません。このような新しいオーバーライドの恩恵を受けるには、アプリケーションを再コンパイルしてください。
QRangeModelAdapter 、QAbstractItemModel 、QStandardItemModel 、および「モデル/ビュープログラミング」も参照してください 。
メンバ型のドキュメント
[since 6.11] enum class QRangeModel::AutoConnectPolicy
この列挙型は、QRangeModel がプロパティの「changed-signals」をモデルのdataChanged()シグナルに自動接続するかどうか、およびそのタイミングを定義します。role names のいずれかに一致するプロパティのみが接続されます。
| 定数 | 値 | 説明 |
|---|---|---|
QRangeModel::AutoConnectPolicy::None | 0 | 自動接続は行われません。 |
QRangeModel::AutoConnectPolicy::Full | 1 | すべてのQObject 項目について、関連するすべてのプロパティのシグナルが自動的に接続されます。これには、新しく挿入された行や列に追加されたQObject 項目も含まれます。 |
QRangeModel::AutoConnectPolicy::OnRead | 2 | 関連するプロパティのシグナルは、モデルがそのプロパティを初めて読み込んだときに接続されます。 |
自動接続を行う際のメモリオーバーヘッドは、かなりのものになる可能性があります。「完全自動接続」では、接続自体以外に管理作業は必要ありませんが、各接続にはメモリが消費され、特にオブジェクトのサブセットのうちごく一部のプロパティのみが変更される場合、すべてのオブジェクトのすべてのプロパティを接続することは非常にコストがかかります。
「OnRead」接続ポリシーでは、一度も読み込まれない(たとえば、ビューでレンダリングされない)オブジェクトやプロパティには接続されませんが、どの接続が行われたかを記憶するには、ある程度の管理オーバーヘッドが必要となり、時間の経過とともに予測不可能なメモリ増加が生じます。たとえば、長いアイテムリストを下にスクロールするだけで、数千もの新しい接続が簡単に生成されてしまう可能性があります。
この列挙型は Qt 6.11 で導入されました。
autoConnectPolicy およびroleNames()も参照してください 。
[since 6.12] enum class QRangeModel::DropOperation
この列挙型は、dropMimeData() のカスタマイズでデコードされたデータが、モデルにどのように書き込まれるかを定義します。
| 定数 | 値 | 説明 |
|---|---|---|
QRangeModel::DropOperation::DontDrop | 0 | データはモデルに追加されない。 |
QRangeModel::DropOperation::Automatic | 1 | Qt が、データがモデルにどのように追加されるかを決定します。 |
QRangeModel::DropOperation::OverwriteAndIgnore | 2 | ドロップ先のアイテムおよびそれ以降のアイテムを上書きし、収まらないドロップされたデータは破棄します。 |
QRangeModel::DropOperation::OverwriteAndExtend | 3 | ドロップ先のアイテムおよびそれ以降のアイテムを上書きし、ドロップされたすべてのデータが収まるようにモデルを拡張します。 |
QRangeModel::DropOperation::InsertAsSiblings | 4 | ドロップされたすべてのデータを、ドロップ先の項目の兄弟要素として挿入します。 |
QRangeModel::DropOperation::InsertAsChildren | 5 | ドロップされたすべてのデータを、ドロップ先の項目の子として挿入します。 |
dropMimeData() をカスタマイズして、代わりに bool 値を返すこともできます。その場合、false は DontDrop 値に、true は Automatic にマップされます。
この列挙型は Qt 6.12 で導入されました。
canDropMimeData() およびdropMimeData()も参照してください 。
enum class QRangeModel::RowCategory
この列挙型は、QRangeModel が、その構築に使用された範囲の要素をどのように表示すべきかを規定するものです。
| 定数 | 値 | 説明 |
|---|---|---|
QRangeModel::RowCategory::Default | 0 | QRangeModel 行の表示方法を決定します。 |
QRangeModel::RowCategory::MultiRoleItem | 1 | QRangeModel は、1 次元範囲で使用される場合でも、メタオブジェクトを持つ項目をマルチロール項目として表示します。 |
RowOptions テンプレートを自身の型用に特化させ、この列挙型の値のいずれかを指定した public メンバー変数static constexpr auto rowCategory を追加してください。
RowOptionsも参照してください 。
プロパティのドキュメント
[since 6.11] autoConnectPolicy : AutoConnectPolicy
モデルがプロパティ変更通知に自動接続する場合。
QRangeModel が、行または項目の型と同じ型のQObject サブクラスを保持するデータ構造を操作する場合、QObjectのプロパティをdataChanged()シグナルに自動的に接続することができます。QObject 行の場合、これは各列に対して行われ、Qt::DisplayRole プロパティにマッピングされます。項目の場合、これはrole names のいずれかに一致するプロパティに対して行われます。
デフォルトでは、このプロパティの値はNone であるため、そのような接続は行われません。このプロパティの値を変更すると、常に既存の接続がすべて切断されます。
注: QRangeModel が操作するデータ構造内の QObject がスワップアウトされても、接続は 切断も作成もされません。
この列挙型は Qt 6.11 で導入されました。
アクセス関数:
| QRangeModel::AutoConnectPolicy | autoConnectPolicy() const |
| void | setAutoConnectPolicy(QRangeModel::AutoConnectPolicy policy) |
Notifierシグナル:
| void | autoConnectPolicyChanged(QRangeModel::AutoConnectPolicy policy) |
関連項目: roleNames()。
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()も参照してください 。
[since 6.12] sortCollator : QCollator
このプロパティには、モデルのソート時に使用されるソート関数が格納されます
このプロパティのデフォルト値は、Cロケール用のQCollator です。ソート処理はロケールを考慮せず、大文字と小文字を区別します。コレーターを設定すると、ソート処理がロケールを考慮するようになります。
この列挙型は Qt 6.12 で導入されました。
アクセス関数:
| QCollator | sortCollator() const |
| void | setSortCollator(const QCollator &collator) |
| void | resetSortCollator() |
通知シグナル:
| void | sortCollatorChanged(const QCollator &collator) |
関連項目: ` sort()`, `sortRole`, および `QSortFilterProxyModel`。
[since 6.12] sortRole : int
このプロパティには、項目の並べ替え時に使用されるデータロールが格納されます。
デフォルト値はQt::DisplayRole です。
この列挙型はQt 6.12で導入されました。
アクセス関数:
| int | sortRole() const |
| void | setSortRole(int role) |
| void | resetSortRole() |
Notifier シグナル:
| void | sortRoleChanged(int role) |
関連項目: sort()、sortCollator 、およびQSortFilterProxyModel 。
[since 6.12] supportedDragActions : Qt::DropActions
このプロパティには、このモデルでサポートされているドラッグ操作が格納されます。
読み取り専用モデルからデータを移動させるなど、モデルがサポートできない操作は、操作を設定する際に削除されます。
注: QRangeModel のサブクラスでこの関数をオーバーライドすることは 可能ですが、プロパティの動作が破損する可能性があります。
この列挙型は Qt 6.12 で導入されました。
アクセス関数:
| virtual Qt::DropActions | supportedDragActions() const override |
| void | setSupportedDragActions(Qt::DropActions actions) |
| void | resetSupportedDragActions() |
Notifier シグナル:
| void | supportedDragActionsChanged(Qt::DropActions actions) |
関連項目: supportedDropActions 。
[since 6.12] supportedDropActions : Qt::DropActions
このプロパティには、このモデルでサポートされているドロップ操作が格納されます。
読み取り専用モデルは、いかなるドロップアクションもサポートできません。
注: QRangeModel のサブクラスでこの関数をオーバーライドすることは 可能ですが、プロパティの動作が破綻する可能性があります。
この列挙型は Qt 6.12 で導入されました。
アクセス関数:
| virtual Qt::DropActions | supportedDropActions() const override |
| void | setSupportedDropActions(Qt::DropActions actions) |
| void | resetSupportedDropActions() |
Notifier シグナル:
| void | supportedDropActionsChanged(Qt::DropActions actions) |
supportedDragActionsも参照してください 。
メンバ関数のドキュメント
[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)
[explicit] template <
typename Range,
typename Protocol,
int = true
>
QRangeModel::QRangeModel(Range &&range, Protocol &&protocol, QObject *parent = nullptr)
range 内のデータを操作するQRangeModel インスタンスを構築します。range は、コンパイラが引数依存検索を通じてbegin およびend のオーバーロードを検出できるシーケンシャル範囲であるか、あるいはstd::begin およびstd::end が実装されている範囲でなければなりません。protocol が指定された場合、モデルはその範囲をプロトコル実装を用いてツリーとして表現します。このモデルインスタンスは、parent の子となります。
range はポインタまたは参照ラッパーである可能性があります。その場合、モデルAPIの変更(setData()やinsertRow()など)によって、参照先の範囲インスタンス内のデータが変更されます。range が値である場合(またはモデル内に移動された場合)、モデルの発行するシグナルに接続して、データの変更に応答します。
QRangeModel このコンストラクタは、構築中にrange にアクセスすることはありません。これにより、例えばsubclassing QRangeModel の場合のように、まだ完全に構築されていない範囲オブジェクトへのポインタや参照をこのコンストラクタに渡すことが許容されます。
range がモデル内に移動された場合、モデルの破棄時に、その範囲およびその中のすべてのデータが破棄されます。
注: モデルは通常、 範囲オブジェクトの所有権を取得しませんが、 モデルが構築され、ビューに渡された後は、 range を直接変更してはなりません。 そのような変更を行うと、モデル利用者(他のモデルやビュー)とモデルとの同期を維持するために必要なシグナルが発信されなくなり、結果として不整合、未定義の挙動、およびクラッシュが発生します。 モデルを最新の状態に保ちつつ、基になる範囲と安全にやり取りするには、`QRangeModelAdapter ` を使用してください。
QRangeModelAdapterも参照してください 。
[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 を再実装します。
範囲に格納されている項目タイプに対してItemAccess のカスタマイズが利用可能であり、そのカスタマイズが適切なcanDropMimeData() クラスメンバ関数を実装している場合、この実装はその関数を呼び出し、その結果を返します。
template <>
struct QRangeModel::ItemAccess<ColorEntry>
{
static bool canDropMimeData(const QMimeData *mimeData)
{
// ...
return true;
}
};それ以外の場合、範囲内の行タイプに対して、適切なcanDropMimeData() クラスメンバ関数を持つRowOptions のカスタマイズが利用可能な場合は、この実装はその関数を呼び出してその結果を返します。
template <>
struct QRangeModel::RowOptions<ColorEntry>
{
static bool canDropMimeData(const QMimeData *mimeData)
{
// ...
return true;
}
};どちらのカスタマイズも利用できない場合、この実装は `QAbstractItemModel ` のデフォルト実装の結果を返します。
Drag'n'drop handling 、RowOptions::canDropMimeData()、ItemAccess::canDropMimeData()、dropMimeData()、mimeTypes()、およびmimeData()も参照してください 。
[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 を再実装します。
index が指す範囲内の値について、指定されたrole の下に格納されているデータを返します。
そのインデックスのアイテム型が、int 、Qt::ItemDataRole 、またはQString のいずれかからQVariant へマッピングする連想コンテナである場合、そのコンテナ内でroleデータが検索され、返されます。
項目がガジェットまたはQObject である場合、実装は、roleNames()のマッピングにおけるrole エントリに一致する項目のプロパティの値を返します。
それ以外の場合、実装は、Qt::DisplayRole またはQt::EditRole に対して、QVariant::fromValue() を介してその項目から構築された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)を再実装します。
範囲に格納されている項目タイプに対してItemAccess のカスタマイズが利用可能であり、そのカスタマイズが適切なdropMimeData() クラスメンバ関数を実装している場合、この実装はその関数を呼び出し、その結果を返します。
template <>
struct QRangeModel::ItemAccess<ColorEntry>
{
static bool dropMimeData(const QMimeData *mimeData, auto inserter)
{
QByteArray data = mimeData->data(mimeTypes().first());
if (data.isEmpty())
return false;
QTextStream stream(&data, QIODevice::ReadOnly);
while (!stream.atEnd()) {
QString colorName;
stream >> colorName;
inserter = ColorEntry(colorName);
}
return true;
}
};それ以外の場合、範囲内の行タイプに対して、適切なdropMimeData() クラスメンバ関数を持つRowOptions のカスタマイズが利用可能な場合、この実装はその関数を呼び出してその結果を返します。
template <>
struct QRangeModel::RowOptions<ColorEntry>
{
static bool dropMimeData(const QMimeData *mimeData, auto inserter)
{
const QByteArray data = mimeData->data(mimeTypes().first());
if (data.isEmpty())
return false;
QXmlStreamReader stream(data);
while (!stream.atEnd()) {
stream.readNext();
if (stream.isStartElement() && stream.name() == u"li"_s)
inserter = ColorEntry(stream.readElementText());
}
return true;
}
};どちらのカスタマイズも利用できない場合、この実装はデフォルトの `QAbstractItemModel ` 実装の結果を返します。
Drag'n'drop handling 、RowOptions::dropMimeData()、ItemAccess::dropMimeData()、canDropMimeData()、mimeTypes()、およびmimeData()も参照してください 。
[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) ようにするフラグも設定します。
mimeTypes() の非空リストを返すモデルも、Qt::ItemIsDragEnabled を設定し、読み取り専用でない限り、Qt::ItemIsDropEnabled フラグも設定します。
フラットモデルはすべての項目に対してQt::ItemNeverHasChildren を設定しますが、階層モデルは0より上の列にあるすべての項目に対してそのフラグを設定します。
独自のデータ型に合わせてフラグをカスタマイズするには、行型または項目型に対して `RowOptions ` および/または `ItemAccess ` の特化型を定義し、静的メンバ関数 `flags()` を実装します。
template <>
struct QRangeModel::ItemAccess<ColorEntry>
{
static Qt::ItemFlags flags(const ColorEntry &entry)
{
return entry.flags();
}
};Qt::ItemFlags 、RowOptions 、およびItemAccessも参照してください 。
[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 を再実装します。
指定されたorientation を持つヘッダー内の、指定されたrole およびsection に対応するデータを返します。
水平ヘッダーの場合、セクション番号は列番号に対応します。同様に、垂直ヘッダーの場合、セクション番号は行番号に対応します。
水平ヘッダーおよびQt::DisplayRole role については、行の型として配列を使用する範囲に対して動作するモデルは、section を返します。行の型がタプルの場合、実装はsection にある型の名前を返します。ガジェットまたはQObject 型の行については、この関数はsection のインデックスにあるプロパティの名前を返します。
独自の範囲の水平ヘッダーデータをカスタマイズするには、行型に対してRowOptions の特化形を定義し、headerData() というクラスメンバー関数を実装します:
template <>
struct QRangeModel::RowOptions<ColorEntry>
{
static QVariant headerData(int section, int role)
{
switch (section) {
// ...
}
return {};
}
};縦方向のヘッダーについては、この関数は常にQAbstractItemModel 内のデフォルト実装の結果を返します。
Qt::ItemDataRole 、setHeaderData()、QHeaderView 、およびRowOptionsも参照してください 。
[override virtual] QModelIndex QRangeModel::index(int row, int column, const QModelIndex &parent = {}) const
QAbstractItemModel::index(int row, int column, const QModelIndex &parent) const の再実装。
parent において、row およびcolumn におけるモデル項目のインデックスを返します。
有効な親を指定すると、リストやテーブルの範囲を操作するモデルでは無効なインデックスが生成されます。
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) を再実装します。
指定されたrow の前に、count の空の行を、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 を再実装します。
flags で定義された一致条件を用いて、role に格納されたデータがvalue と一致する、start の列内の項目のインデックスのリストを返します。hits = -1 を使用すると、一致するすべての項目を検索できます。
注:この実装では 、基盤となる C++ 範囲から直接データを読み取り、data() のオーバーライドを経由して処理を行いません。
[override virtual] QMimeData *QRangeModel::mimeData(const QModelIndexList &indexes) const
QAbstractItemModel::mimeData(const QModelIndexList &indexes) const を再実装します。
範囲内に格納されている項目型に対してItemAccess のカスタマイズが利用可能であり、かつそのカスタマイズが適切なmimeData()クラスメンバ関数を実装している場合、この実装はその関数を呼び出し、その結果を返します。
template <>
struct QRangeModel::ItemAccess<ColorEntry>
{
static QMimeData *mimeData(const auto &range)
{
QByteArray data;
QTextStream stream(&data, QIODevice::WriteOnly);
for (const auto &[item, index] : range)
stream << item.colorName() << Qt::endl;
QMimeData *result = new QMimeData;
result->setData(mimeTypes().first(), data);
// Qt handles encoding into the default mime type
return result;
}
};そうでない場合、範囲内の行型に対して、適切な `mimeData()` クラスメンバ関数を持つ `RowOptions ` のカスタマイズが利用可能な場合、この実装はその関数を呼び出して結果を返します。
template <>
struct QRangeModel::RowOptions<ColorEntry>
{
template <typename Items>
static QMimeData *mimeData(const Items &items)
{
if (items.isEmpty())
return nullptr;
QByteArray data;
QXmlStreamWriter stream(&data);
stream.writeStartElement("ul");
for (const auto &[item, index] : items)
stream.writeTextElement("li", item.colorName());
stream.writeEndElement();
QMimeData *mimeData = new QMimeData;
mimeData->setData(mimeTypes().first(), data);
return mimeData;
}
};どちらのカスタマイズも利用できない場合、この実装はQAbstractItemModel のデフォルト実装の結果を返します。
Drag'n'drop handling 、RowOptions::mimeData()、ItemAccess::mimeData()、canDropMimeData()、dropMimeData()、およびmimeTypes()も参照してください 。
[override virtual] QStringList QRangeModel::mimeTypes() const
QAbstractItemModel::mimeTypes() const を再実装します。
範囲に格納されている項目型に対してItemAccess のカスタマイズが利用可能であり、かつそのカスタマイズが適切なmimeTypes()クラスメンバ関数を実装している場合、この実装はその関数を呼び出し、その結果を返します。
template <>
struct QRangeModel::ItemAccess<ColorEntry>
{
static QStringList mimeTypes()
{
return {
u"text/plain"_s,
u"application/x-qabstractitemmodeldatalist"_s
};
}
};それ以外の場合、範囲内の行型に対して、適切な `mimeTypes()` クラスメンバ関数を持つ `RowOptions ` のカスタマイズが利用可能な場合、この実装はその関数を呼び出してその結果を返します。
template <>
struct QRangeModel::RowOptions<ColorEntry>
{
static QStringList mimeTypes()
{
return {
u"text/html"_s
};
}
};どちらのカスタマイズも利用できない場合、この実装はQAbstractItemModel のデフォルトの実装の結果を返します。
Drag'n'drop handling 、RowOptions::mimeTypes()、ItemAccess::mimeTypes()、canDropMimeData()、dropMimeData()、およびmimeData()も参照してください 。
[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)。
指定されたsourceRow から始まるcount の行を、親sourceParent の下から、親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) const を再実装します。
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) を再実装します。
範囲parent のすべての行において、column にある項目から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) を再実装します。
parent にある範囲から、指定されたrow を起点として、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() const を再実装します。
注: 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 へのマッピングを行う場合、role names テーブルにマッピングが存在するdata 内の値のみが格納されます。
アイテムのタイプがガジェットまたは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) const を再実装します。
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) を再実装します。
column 内の項目のsortRole (デフォルトではQt::DisplayRole )のデータに基づいて、指定されたorder に従って、基となる範囲をソートします。
注:この実装では 、C++の範囲にsort(Compare comp) というメンバ関数が利用可能な場合(std::list など)、それを使用します。そうでない場合、範囲がランダムアクセスイテレータを提供している場合はstd::stable_sort() を使用します。どちらも利用できない場合、実装は何も行わず、直ちに返却します。
注: 項目へのアクセスを行っても 、data() のオーバーライドを介してデータの読み取りがディスパッチされることはありません。
sortRole およびQSortFilterProxyModelも参照してください 。
[override virtual] QSize QRangeModel::span(const QModelIndex &index) const
QAbstractItemModel::span(const QModelIndex &index) const を再実装します。
© 2026 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.