Флажки QTreeView
Я знаю, что об этом спрашивали много раз, но я не могу найти что-то уместное.
Используя учебное пособие simpletreemodel, которое поставляется в комплекте с Qt, как я бы добавил флажки?
3 ответа
Во-первых, вам нужно изменить TreeItem, чтобы отслеживать проверенное состояние:
И сеттер и геттер:
Теперь необходимо изменить модель, чтобы представление узнало о состоянии проверки:
И измените метод flags модели, чтобы представления знали, что модель содержит проверяемые элементы:
Я думаю, что это должно сделать это. Если вы хотите иметь возможность обновлять состояние проверки TreeItem, когда пользователь выбирает и снимает отметку с элементов, то вам нужно предоставить метод QAbstractItemModel :: setData в TreeModel.
Я преобразовал вышеупомянутое в PyQt для своих собственных целей и решил поделиться.
Вот еще один пример полного пробуждения PyQt с использованием QStandardItemModel :
Как установить ItemFlag в QTreeView или QListView?
ОБНОВЛЕНИЕ 1: QTreeView основан на QFileSystemModel().
Как установить флаги для указанного элемента дерева?
в подклассе QFileSystemModel()?
Ответы (1)
Я черпал вдохновение отсюда: TreeView в Python+QT
Подобно setData(), вы не можете установить Data() в QFileSystemModel, но вы можете изменить data(), чтобы добавить свой код при чтении данных из модели.
Вы не можете напрямую установитьFlags() в QFileSystemModel, но вы можете изменить flags() для изменения возвращаемых данных.
QTreeView Class
A QTreeView implements a tree representation of items from a model. This class is used to provide standard hierarchical lists that were previously provided by the QListView class, but using the more flexible approach provided by Qt’s model/view architecture.
The QTreeView class is one of the Model/View Classes and is part of Qt’s model/view framework.
QTreeView implements the interfaces defined by the QAbstractItemView class to allow it to display data provided by models derived from the QAbstractItemModel class.
It is simple to construct a tree view displaying data from a model. In the following example, the contents of a directory are supplied by a QFileSystemModel and displayed as a tree:
The model/view architecture ensures that the contents of the tree view are updated as the model changes.
Items that have children can be in an expanded (children are visible) or collapsed (children are hidden) state. When this state changes a collapsed() or expanded() signal is emitted with the model index of the relevant item.
The amount of indentation used to indicate levels of hierarchy is controlled by the indentation property.
Headers in tree views are constructed using the QHeaderView class and can be hidden using header()->hide() . Note that each header is configured with its stretchLastSection property set to true, ensuring that the view does not waste any of the space assigned to it for its header. If this value is set to true, this property will override the resize mode set on the last section in the header.
By default, all columns in a tree view are movable except the first. To disable movement of these columns, use QHeaderView’s setSectionsMovable() function. For more information about rearranging sections, see Moving Header Sections.
Key Bindings
QTreeView supports a set of key bindings that enable the user to navigate in the view and interact with the contents of items:
Key | Action |
---|---|
Up | Moves the cursor to the item in the same column on the previous row. If the parent of the current item has no more rows to navigate to, the cursor moves to the relevant item in the last row of the sibling that precedes the parent. |
Down | Moves the cursor to the item in the same column on the next row. If the parent of the current item has no more rows to navigate to, the cursor moves to the relevant item in the first row of the sibling that follows the parent. |
Left | Hides the children of the current item (if present) by collapsing a branch. |
Minus | Same as Left. |
Right | Reveals the children of the current item (if present) by expanding a branch. |
Plus | Same as Right. |
Asterisk | Expands the current item and all its children (if present). |
PageUp | Moves the cursor up one page. |
PageDown | Moves the cursor down one page. |
Home | Moves the cursor to an item in the same column of the first row of the first top-level item in the model. |
End | Moves the cursor to an item in the same column of the last row of the last top-level item in the model. |
F2 | In editable models, this opens the current item for editing. The Escape key can be used to cancel the editing process and revert any changes to the data displayed. |
Improving Performance
It is possible to give the view hints about the data it is handling in order to improve its performance when displaying large numbers of items. One approach that can be taken for views that are intended to display items with equal heights is to set the uniformRowHeights property to true.
Property Documentation
allColumnsShowFocus : bool
This property holds whether items should show keyboard focus using all columns
If this property is true all columns will show focus, otherwise only one column will show focus.
The default is false.
Access functions:
bool | allColumnsShowFocus () const |
void | setAllColumnsShowFocus (bool enable) |
animated : bool
This property holds whether animations are enabled
If this property is true the treeview will animate expansion and collapsing of branches. If this property is false , the treeview will expand or collapse branches immediately without showing the animation.
By default, this property is false .
Access functions:
bool | isAnimated () const |
void | setAnimated (bool enable) |
autoExpandDelay : int
This property holds the delay time before items in a tree are opened during a drag and drop operation.
This property holds the amount of time in milliseconds that the user must wait over a node before that node will automatically open or close. If the time is set to less then 0 then it will not be activated.
By default, this property has a value of -1, meaning that auto-expansion is disabled.
Access functions:
int | autoExpandDelay () const |
void | setAutoExpandDelay (int delay) |
expandsOnDoubleClick : bool
This property holds whether the items can be expanded by double-clicking.
This property holds whether the user can expand and collapse items by double-clicking. The default value is true.
Access functions:
bool | expandsOnDoubleClick () const |
void | setExpandsOnDoubleClick (bool enable) |
headerHidden : bool
This property holds whether the header is shown or not.
If this property is true , the header is not shown otherwise it is. The default value is false.
Access functions:
bool | isHeaderHidden () const |
void | setHeaderHidden (bool hide) |
indentation : int
indentation of the items in the tree view.
This property holds the indentation measured in pixels of the items for each level in the tree view. For top-level items, the indentation specifies the horizontal distance from the viewport edge to the items in the first column; for child items, it specifies their indentation from their parent items.
By default, the value of this property is style dependent. Thus, when the style changes, this property updates from it. Calling setIndentation() stops the updates, calling resetIndentation() will restore default behavior.
Access functions:
int | indentation () const |
void | setIndentation (int i) |
void | resetIndentation () |
itemsExpandable : bool
This property holds whether the items are expandable by the user.
This property holds whether the user can expand and collapse items interactively.
By default, this property is true .
Access functions:
bool | itemsExpandable () const |
void | setItemsExpandable (bool enable) |
rootIsDecorated : bool
This property holds whether to show controls for expanding and collapsing top-level items
Items with children are typically shown with controls to expand and collapse them, allowing their children to be shown or hidden. If this property is false, these controls are not shown for top-level items. This can be used to make a single level tree structure appear like a simple list of items.
By default, this property is true .
Access functions:
bool | rootIsDecorated () const |
void | setRootIsDecorated (bool show) |
sortingEnabled : bool
This property holds whether sorting is enabled
If this property is true , sorting is enabled for the tree; if the property is false, sorting is not enabled. The default value is false.
Note: In order to avoid performance issues, it is recommended that sorting is enabled after inserting the items into the tree. Alternatively, you could also insert the items into a list before inserting the items into the tree.
Access functions:
bool | isSortingEnabled () const |
void | setSortingEnabled (bool enable) |
uniformRowHeights : bool
This property holds whether all items in the treeview have the same height
This property should only be set to true if it is guaranteed that all items in the view has the same height. This enables the view to do some optimizations.
The height is obtained from the first item in the view. It is updated when the data changes on that item.
Note: If the editor size hint is bigger than the cell size hint, then the size hint of the editor will be used.
By default, this property is false .
Access functions:
bool | uniformRowHeights () const |
void | setUniformRowHeights (bool uniform) |
wordWrap : bool
This property holds the item text word-wrapping policy
If this property is true then the item text is wrapped where necessary at word-breaks; otherwise it is not wrapped at all. This property is false by default.
Note that even if wrapping is enabled, the cell will not be expanded to fit all text. Ellipsis will be inserted according to the current textElideMode.
Access functions:
bool | wordWrap () const |
void | setWordWrap (bool on) |
Member Function Documentation
QTreeView:: QTreeView ( QWidget *parent = nullptr)
Constructs a tree view with a parent to represent a model’s data. Use setModel() to set the model.
[slot] void QTreeView:: collapse (const QModelIndex &index)
Collapses the model item specified by the index.
[slot] void QTreeView:: collapseAll ()
Collapses all expanded items.
[signal] void QTreeView:: collapsed (const QModelIndex &index)
This signal is emitted when the item specified by index is collapsed.
[protected slot] void QTreeView:: columnCountChanged ( int oldCount, int newCount)
Informs the tree view that the number of columns in the tree view has changed from oldCount to newCount.
[protected slot] void QTreeView:: columnMoved ()
This slot is called whenever a column has been moved.
[protected slot] void QTreeView:: columnResized ( int column, int oldSize, int newSize)
This function is called whenever column‘s size is changed in the header. oldSize and newSize give the previous size and the new size in pixels.
[slot] void QTreeView:: expand (const QModelIndex &index)
Expands the model item specified by the index.
[slot] void QTreeView:: expandAll ()
Expands all expandable items.
Note: This function will not try to fetch more data.
Warning: If the model contains a large number of items, this function will take some time to execute.
[slot, since 5.13] void QTreeView:: expandRecursively (const QModelIndex &index, int depth = -1)
Expands the item at the given index and all its children to the given depth. The depth is relative to the given index. A depth of -1 will expand all children, a depth of 0 will only expand the given index.
Note: This function will not try to fetch more data.
Warning: If the model contains a large number of items, this function will take some time to execute.
This function was introduced in Qt 5.13.
[slot] void QTreeView:: expandToDepth ( int depth)
Expands all expandable items to the given depth.
Note: This function will not try to fetch more data.
[signal] void QTreeView:: expanded (const QModelIndex &index)
This signal is emitted when the item specified by index is expanded.
[slot] void QTreeView:: hideColumn ( int column)
Hides the column given.
Note: This function should only be called after the model has been initialized, as the view needs to know the number of columns in order to hide column.
[slot] void QTreeView:: resizeColumnToContents ( int column)
Resizes the column given to the size of its contents.
[protected slot] void QTreeView:: rowsRemoved (const QModelIndex &parent, int start, int end)
Informs the view that the rows from the start row to the end row inclusive have been removed from the given parent model item.
[slot] void QTreeView:: showColumn ( int column)
Shows the given column in the tree view.
[slot] void QTreeView:: sortByColumn ( int column, Qt::SortOrder order)
Sorts the model by the values in the given column and order.
column may be -1, in which case no sort indicator will be shown and the model will return to its natural, unsorted order. Note that not all models support this and may even crash in this case.
[virtual] QTreeView::
Destroys the tree view.
[override virtual protected] void QTreeView:: changeEvent ( QEvent *event)
int QTreeView:: columnAt ( int x) const
Returns the column in the tree view whose header covers the x coordinate given.
int QTreeView:: columnViewportPosition ( int column) const
Returns the horizontal position of the column in the viewport.
int QTreeView:: columnWidth ( int column) const
Returns the width of the column.
[override virtual protected] void QTreeView:: currentChanged (const QModelIndex ¤t, const QModelIndex &previous)
Reimplements: QAbstractItemView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous).
[override virtual] void QTreeView:: dataChanged (const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList < int > &roles = QList<int>())
Reimplements: QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles).
[override virtual protected] void QTreeView:: dragMoveEvent ( QDragMoveEvent *event)
[virtual protected] void QTreeView:: drawBranches ( QPainter *painter, const QRect &rect, const QModelIndex &index) const
Draws the branches in the tree view on the same row as the model item index, using the painter given. The branches are drawn in the rectangle specified by rect.
[virtual protected] void QTreeView:: drawRow ( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
Draws the row in the tree view that contains the model item index, using the painter given. The option controls how the item is displayed.
[protected] void QTreeView:: drawTree ( QPainter *painter, const QRegion ®ion) const
Draws the part of the tree intersecting the given region using the specified painter.
QHeaderView *QTreeView:: header () const
Returns the header for the tree view.
[override virtual protected] int QTreeView:: horizontalOffset () const
Returns the horizontal offset of the items in the treeview.
Note that the tree view uses the horizontal header section positions to determine the positions of columns in the view.
QModelIndex QTreeView:: indexAbove (const QModelIndex &index) const
Returns the model index of the item above index.
[override virtual] QModelIndex QTreeView:: indexAt (const QPoint &point) const
QModelIndex QTreeView:: indexBelow (const QModelIndex &index) const
Returns the model index of the item below index.
[protected] int QTreeView:: indexRowSizeHint (const QModelIndex &index) const
Returns the size hint for the row indicated by index.
bool QTreeView:: isColumnHidden ( int column) const
Returns true if the column is hidden; otherwise returns false .
bool QTreeView:: isExpanded (const QModelIndex &index) const
Returns true if the model item index is expanded; otherwise returns false.
bool QTreeView:: isFirstColumnSpanned ( int row, const QModelIndex &parent) const
Returns true if the item in first column in the given row of the parent is spanning all the columns; otherwise returns false .
[override virtual protected] bool QTreeView:: isIndexHidden (const QModelIndex &index) const
bool QTreeView:: isRowHidden ( int row, const QModelIndex &parent) const
Returns true if the item in the given row of the parent is hidden; otherwise returns false .
[override virtual protected] void QTreeView:: keyPressEvent ( QKeyEvent *event)
[override virtual] void QTreeView:: keyboardSearch (const QString &search)
[override virtual protected] void QTreeView:: mouseDoubleClickEvent ( QMouseEvent *event)
[override virtual protected] void QTreeView:: mouseMoveEvent ( QMouseEvent *event)
[override virtual protected] void QTreeView:: mousePressEvent ( QMouseEvent *event)
[override virtual protected] void QTreeView:: mouseReleaseEvent ( QMouseEvent *event)
[override virtual protected] QModelIndex QTreeView:: moveCursor ( QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
Reimplements: QAbstractItemView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers).
Move the cursor in the way described by cursorAction, using the information provided by the button modifiers.
[override virtual protected] void QTreeView:: paintEvent ( QPaintEvent *event)
[override virtual] void QTreeView:: reset ()
[protected] int QTreeView:: rowHeight (const QModelIndex &index) const
Returns the height of the row indicated by the given index.
[override virtual protected] void QTreeView:: rowsAboutToBeRemoved (const QModelIndex &parent, int start, int end)
Reimplements: QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end).
Informs the view that the rows from the start row to the end row inclusive are about to removed from the given parent model item.
[override virtual protected] void QTreeView:: rowsInserted (const QModelIndex &parent, int start, int end)
Reimplements: QAbstractItemView::rowsInserted(const QModelIndex &parent, int start, int end).
Informs the view that the rows from the start row to the end row inclusive have been inserted into the parent model item.
[override virtual protected] void QTreeView:: scrollContentsBy ( int dx, int dy)
Scrolls the contents of the tree view by (dx, dy).
[override virtual] void QTreeView:: scrollTo (const QModelIndex &index, QAbstractItemView::ScrollHint hint = EnsureVisible)
Reimplements: QAbstractItemView::scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint hint).
Scroll the contents of the tree view until the given model item index is visible. The hint parameter specifies more precisely where the item should be located after the operation. If any of the parents of the model item are collapsed, they will be expanded to ensure that the model item is visible.
[override virtual] void QTreeView:: selectAll ()
[override virtual protected] QModelIndexList QTreeView:: selectedIndexes () const
[override virtual protected] void QTreeView:: selectionChanged (const QItemSelection &selected, const QItemSelection &deselected)
Reimplements: QAbstractItemView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected).
void QTreeView:: setColumnHidden ( int column, bool hide)
If hide is true the column is hidden, otherwise the column is shown.
void QTreeView:: setColumnWidth ( int column, int width)
Sets the width of the given column to the width specified.
void QTreeView:: setExpanded (const QModelIndex &index, bool expanded)
Sets the item referred to by index to either collapse or expanded, depending on the value of expanded.
void QTreeView:: setFirstColumnSpanned ( int row, const QModelIndex &parent, bool span)
If span is true the item in the first column in the row with the given parent is set to span all columns, otherwise all items on the row are shown.
void QTreeView:: setHeader ( QHeaderView *header)
Sets the header for the tree view, to the given header.
The view takes ownership over the given header and deletes it when a new header is set.
[override virtual] void QTreeView:: setModel ( QAbstractItemModel *model)
Reimplements: QAbstractItemView::setModel(QAbstractItemModel *model).
[override virtual] void QTreeView:: setRootIndex (const QModelIndex &index)
void QTreeView:: setRowHidden ( int row, const QModelIndex &parent, bool hide)
If hide is true the row with the given parent is hidden, otherwise the row is shown.
[override virtual protected] void QTreeView:: setSelection (const QRect &rect, QItemSelectionModel::SelectionFlags command)
Reimplements: QAbstractItemView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags flags).
Applies the selection command to the items in or touched by the rectangle, rect.
[override virtual] void QTreeView:: setSelectionModel ( QItemSelectionModel *selectionModel)
Reimplements: QAbstractItemView::setSelectionModel(QItemSelectionModel *selectionModel).
[since 5.2] void QTreeView:: setTreePosition ( int index)
This specifies that the tree structure should be placed at logical index index. If set to -1 then the tree will always follow visual index 0.
This function was introduced in Qt 5.2.
[override virtual protected] int QTreeView:: sizeHintForColumn ( int column) const
Returns the size hint for the column‘s width or -1 if there is no model.
If you need to set the width of a given column to a fixed value, call QHeaderView::resizeSection() on the view’s header.
If you reimplement this function in a subclass, note that the value you return is only used when resizeColumnToContents() is called. In that case, if a larger column width is required by either the view’s header or the item delegate, that width will be used instead.
[override virtual protected] void QTreeView:: timerEvent ( QTimerEvent *event)
[since 5.2] int QTreeView:: treePosition () const
Return the logical index the tree is set on. If the return value is -1 then the tree is placed on the visual index 0.
This function was introduced in Qt 5.2.
[override virtual protected] void QTreeView:: updateGeometries ()
[override virtual protected] int QTreeView:: verticalOffset () const
Returns the vertical offset of the items in the tree view.
[override virtual protected] bool QTreeView:: viewportEvent ( QEvent *event)
[override virtual protected] QSize QTreeView:: viewportSizeHint () const
[override virtual] QRect QTreeView:: visualRect (const QModelIndex &index) const
Returns the rectangle on the viewport occupied by the item at index. If the index is not visible or explicitly hidden, the returned rectangle is invalid.
[override virtual protected] QRegion QTreeView:: visualRegionForSelection (const QItemSelection &selection) const
Returns the rectangle from the viewport of the items in the given selection.
Since 4.7, the returned region only contains rectangles intersecting (or included in) the viewport.
© 2023 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.
Пример редактируемой древовидной модели в проекте с Qt
В данном примере показано, как реализовать простую редактируемую древовидную модель на основе элементов, которую можно использовать с другими классами фреймворка модель/представление.
Данная модель поддерживает редактируемые элементы, настраиваемые заголовки и возможность вставки и удаления строк и столбцов. С помощью этих функций также можно вставлять новые дочерние элементы, и это показано во вспомогательном коде примера.
Обзор
Как описано в справке по созданию подклассов моделей, модели должны предоставлять реализации для стандартного набора функций модели: flags() , data() , headerData() , columnCount() и rowCount() . Кроме того, иерархические модели, такие как эта, должны обеспечивать реализации index() и parent() .
Редактируемая модель также должна предоставлять реализации setData() и setHeaderData() и должна возвращать подходящую комбинацию флагов из своей функции flags() .
Поскольку данный пример позволяет изменять размеры модели, мы также должны реализовать функции insertRows() , insertColumns() , removeRows() и removeColumns() .
Проектирование
Как и в примере с простой древовидной моделью, эта модель действует просто как обертка для коллекции экземпляров класса TreeItem . Каждый TreeItem предназначен для хранения данных для строки элементов в представлении в виде дерева, и поэтому он содержит список значений, соответствующих данным, отображаемым в каждом столбце.
Поскольку QTreeView обеспечивает ориентированное на строки представление модели, естественно выбрать ориентированное на строки проектирование для структур данных, которые будут предоставлять данные через модель для такого вида представления. Хотя это делает древовидную модель менее гибкой и, возможно, менее полезной для использования с более сложными представлениями, это также делает ее менее сложной в разработке и более простой в реализации.
Связи между внутренними элементами
При проектировании структуры данных для пользовательской модели полезно предоставлять родительский объект каждого элемента с помощью такой функции, как TreeItem::parent() , потому что это упростит написание собственной функции parent() в модели. Точно так же функция TreeItem::child() полезна при реализации функции index() модели. В результате каждый TreeItem хранит информацию о своих родителе и дочерних элементах, что позволяет нам перемещаться по древовидной структуре.
На диаграмме ниже показано, как экземпляры TreeItem связаны через свои функции parent() и child() .
В показанном примере два элемента верхнего уровня, A и B, могут быть получены из корневого элемента путем вызова его функции child() , и каждый из этих элементов возвращает корневой узел из своей функции parent() , хотя это только показано для узла А.
Каждый TreeItem хранит данные для каждого столбца в строке, которую он представляет, в своем закрытом члене itemData (список объектов QVariant ). Поскольку между каждым столбцом в представлении и каждой записью в списке существует взаимно однозначное соответствие, мы предоставляем простую функцию data() для чтения записей в списке itemData и функцию setData() , позволяющую их модифицировать. Как и в случае с другими функциями в элементе, это упрощает реализацию функций модели data() и setData() .
Мы помещаем элемент в корень дерева элементов. Этот корневой элемент соответствует нулевому индексу модели, QModelIndex() , который используется для представления родителя элемента верхнего уровня при обработке индексов модели. Хотя корневой элемент не имеет видимого представления ни в одном из стандартных представлений, мы используем его внутренний список объектов QVariant для хранения списка строк, которые будут переданы представлениям для использования в качестве контента горизонтальных заголовков.
Доступ к данным через модель
В случае, показанном на диаграмме, часть информации, представленная в a, может быть получена с использованием стандартного API модель/представление:
Поскольку каждый элемент содержит фрагменты данных для каждого столбца в заданной строке, может быть много модельных индексов, которые сопоставляются с одним и тем же объектом TreeItem . Например, информацию, представленную в b, можно получить с помощью следующего кода:
Доступ к тому же базовому элементу TreeItem будет осуществляться для получения информации о других индексах модели в той же строке, что и b.
В классе модели TreeModel мы связываем объекты TreeItem с индексами модели, передавая указатель для каждого элемента при создании соответствующего индекса модели с помощью QAbstractItemModel::createIndex() в наших реализациях index() и parent() . Сохраненные таким образом указатели мы можем получить, вызвав функцию internalPointer() для соответствующего индекса модели – мы создадим собственную функцию getItem() , которая сделает всю работу за нас, и вызываем ее из наших реализаций data() и parent() .
Хранение указателей на элементы удобно, когда мы контролируем, как они создаются и уничтожаются, поскольку мы можем предположить, что адрес, полученный из internalPointer() , является допустимым указателем. Однако некоторым моделям необходимо обрабатывать элементы, получаемые из других компонентов системы, и во многих случаях невозможно полностью контролировать создание или уничтожение элементов. В таких ситуациях подход, основанный исключительно на указателях, должен быть дополнен мерами безопасности, чтобы гарантировать, что модель не попытается получить доступ к удаленным элементам.
Хранение информации в базовой структуре данных
Несколько фрагментов данных хранятся как объекты QVariant в члене itemData каждого экземпляра TreeItem .
На диаграмме ниже показано, как фрагменты информации, представленные метками a, b и c на предыдущей диаграммах, хранятся в элементах A, B и C базовой структуры данных. Обратите внимание, что все части информации из одной и той же строки в модели получены из одного и того же элемента. Каждый элемент в списке соответствует части информации, предоставляемой каждым столбцом в данной строке модели.
Поскольку реализация TreeModel была разработана для использования с QTreeView , мы добавили ограничение на способ использования экземпляров TreeItem : каждый элемент должен предоставлять одинаковое количество столбцов данных. Это делает просмотр модели согласованным, позволяя нам использовать корневой элемент для определения количества столбцов для любой заданной строки, и только добавляет требование, чтобы мы создавали элементы, содержащие достаточно данных для общего числа столбцов. В результате вставка и удаление столбцов являются трудоемкими операциями, поскольку нам нужно пройти все дерево, чтобы изменить каждый элемент.
Альтернативным подходом может быть разработка класса TreeModel таким образом, чтобы он усекал или расширял список данных в отдельных экземплярах TreeItem по мере изменения элементов данных. Однако этот «ленивый» подход к изменению размера позволил бы нам вставлять и удалять столбцы только в конец каждой строки и не позволял бы вставлять или удалять столбцы в произвольных позициях в каждой строке.
Связь элементов с использованием индексов модели
Как и в примере с простой древовидной моделью, TreeModel должен иметь возможность брать индекс модели, находить соответствующий TreeItem и возвращать индексы модели, соответствующие его родительскому и дочерним элементам.
На диаграмме ниже показано, как реализация parent() в модели получает индекс модели, соответствующий родителю элемента, предоставленного вызывающим, используя элементы, показанные на предыдущей диаграмме.
Указатель на элемент C получается из соответствующего индекса модели с помощью функции QModelIndex::internalPointer() . Этот указатель был сохранен внутри индекса при его создании. Поскольку дочерний элемент содержит указатель на своего родителя, мы используем его функцию parent() для получения указателя на элемент B. Индекс модели для родителя создается с помощью функции QAbstractItemModel::createIndex() , в которую передается указатель на элемент B в качестве внутреннего указателя.
Определение класса TreeItem
Класс TreeItem предоставляет простые элементы, которые содержат несколько фрагментов данных, включая информацию об их родительских и дочерних элементах:
Мы разработали API таким образом, чтобы он был похож на предоставляемый QAbstractItemModel , предоставив каждому элементу функции для возврата количества столбцов информации, чтения и записи данных, а также вставки и удаления столбцов. Однако мы здесь делаем связи между элементами явными, предоставляя функции для работы с «дочерними элементами», а не со «строками».
Каждый элемент содержит список указателей на дочерние элементы, указатель на свой родительский элемент и список объектов QVariant , которые соответствуют информации, содержащейся в столбцах данной строки в модели.
Реализация класса TreeItem
Каждый TreeItem состоит из списка данных и необязательного родительского элемента:
Изначально у каждого элемента нет потомков. Они добавляются во внутренний член childItems с помощью функции insertChildren() , описанной ниже.
Деструктор гарантирует, что каждый дочерний элемент, добавленный к элементу, будет удален при удалении самого элемента:
Поскольку каждый элемент хранит указатель на своего родителя, функция parent() тривиальна:
Информацию о дочерних элементах элемента предоставляют три функции. child() возвращает конкретный дочерний элемент из внутреннего списка дочерних элементов:
Функция childCount() возвращает количество дочерних элементов:
Функция childNumber() используется для определения индекса дочернего элемента в родительском списке дочерних элементов. Она напрямую обращается к элементу childItems родителя, чтобы получить эту информацию:
Корневой элемент не имеет родительского элемента; для него мы возвращаем ноль, чтобы он соответствовал другим элементам.
Функция columnCount() просто возвращает количество элементов во внутреннем списке itemData объектов QVariant :
Данные извлекаются с помощью функции data() , которая обращается к соответствующему элементу в списке itemData :
Данные устанавливаются с помощью функции setData() , которая сохраняет значения в списке itemData только для допустимых индексов списка, соответствующих значениям столбца в модели:
Чтобы упростить реализацию модели, мы возвращаем значение true , чтобы указать, что данные были установлены успешно.
Редактируемые модели часто должны изменять размер, позволяя вставлять и удалять строки и столбцы. Вставка строк в модель под заданным индексом модели приводит к вставке новых дочерних элементов в соответствующий элемент, обрабатываемый функцией insertChildren() :
Это гарантирует, что новые элементы будут созданы с необходимым количеством столбцов и вставлены в допустимую позицию во внутреннем списке дочерних элементов. Удаляются элементы с помощью функции removeChildren() :
Как обсуждалось выше, функции для вставки и удаления столбцов используются иначе, чем функции для вставки и удаления дочерних элементов, поскольку ожидается, что они будут вызываться для каждого элемента в дереве. Мы делаем это, рекурсивно вызывая эту функцию для каждого потомка элемента:
Определение класса TreeModel
Класс TreeModel предоставляет реализацию класса QAbstractItemModel , предоставляя необходимый интерфейс для модели, которую можно редактировать и изменять размер.
Конструктор и деструктор специфичны для этой модели.
Древовидные модели только для чтения должны обеспечивать только приведенные выше функции. Следующие открытые функции обеспечивают поддержку редактирования и изменения размера:
Чтобы упростить этот пример, данные, предоставляемые моделью, организованы в структуру данных с помощью функции модели setupModelData() . Многие реальные модели вообще не обрабатывают сырые данные, а просто работают с существующей структурой данных или библиотечным API.
Реализация класса TreeModel
Конструктор создает корневой элемент и инициализирует его предоставленными данными заголовков:
Мы вызываем внутреннюю функцию setupModelData() для преобразования предоставленных текстовых данных в структуру данных, которую мы можем использовать с данной моделью. Другие модели могут быть инициализированы готовой структурой данных или использовать API из библиотеки, которая поддерживает свои собственные данные.
Деструктор должен удалять только корневой элемент, что приведет к рекурсивному удалению всех дочерних элементов.
Поскольку интерфейс модели с другими компонентами архитектуры модель/представление основан на индексах модели, а внутренняя структура данных основана на элементах, многие функции, реализованные моделью, должны иметь возможность преобразовывать любой заданный индекс модели в соответствующий элемент. Для удобства и согласованности мы определили функцию getItem() для выполнения этой повторяющейся задачи:
Каждый индекс модели, переданный этой функции, должен соответствовать действительному элементу в памяти. Если индекс недействителен или его внутренний указатель не ссылается на допустимый элемент, вместо него возвращается корневой элемент.
Реализация модели rowCount() проста: сначала используется функция getItem() для получения соответствующего элемента; а затем он возвращает количество дочерних элементов, которые содержит:
Для реализации columnCount() , напротив, не нужно искать конкретный элемент, потому что все элементы определены как имеющие одинаковое количество связанных с ними столбцов.
В результате количество столбцов можно получить непосредственно из корневого элемента.
Чтобы разрешить редактирование и выбор элементов, функция flags() должна быть реализована так, чтобы она возвращала комбинацию флагов, включающую флаги Qt::ItemIsEditable и Qt::ItemIsSelectable , а также Qt::ItemIsEnabled :
Модель должна иметь возможность генерировать индексы, чтобы другие компоненты могли запрашивать данные и информацию о ее структуре. Эта задача выполняется функцией index() , которая используется для получения индексов модели, соответствующих дочерним элементам заданного родительского элемента:
В этой модели мы возвращаем индексы для дочерних элементов только в том случае, если родительский индекс недействителен (соответствует корневому элементу) или имеет нулевой номер столбца.
Мы используем пользовательскую функцию getItem() для получения экземпляра TreeItem , соответствующего предоставленному индексу модели, и запрашиваем его дочерний элемент, соответствующий указанной строке.
Поскольку каждый элемент содержит информацию для всей строки данных, мы создаем индекс модели, чтобы однозначно идентифицировать его, вызывая его createIndex() с номерами строки и столбца и указателем на элемент. В функции data() мы будем использовать указатель элемента и номер столбца для доступа к данным, связанным с индексом модели; в этой модели номер строки не требуется для идентификации данных.
Функция parent() предоставляет индексы модели для родителей элементов, находя соответствующий элемент для данного индекса модели, используя функцию parent() для получения его родительского элемента, а затем создавая индекс модели для представления родителя (смотрите приведенную выше диаграмму).
Элементы без родителей, включая корневой элемент, обрабатываются путем возврата нулевого индекса модели. В противном случае индекс модели создается и возвращается, как в функции index() , с соответствующим номером строки, но с нулевым номером столбца, чтобы соответствовать схеме, используемой в реализации index() .
Данные из модели получаются через функцию data() . Поскольку элемент сам управляет своими столбцами, то для получения данных с помощью функции TreeItem::data() нам нужно использовать номер столбца:
Для редактирования данных используется функции setData() . Здесь мы так же получаем элемент TreeItem , а затем вызываем его функцию setData() . И в случае успеха выдаем сигнал dataChanged() .
Для получения и изменения данных заголовков функции headerData() и setHeaderData() модели используют функции data() и setData() корневого элемента.
При вставке строк мы получаем родительский элемент и добавляем указанное количество дочерних элементов в указанную позицию с помощью функции insertChildren() класса TreeItem .
Для удаления строк действуем аналогично.
Для манипуляций со столбцами вызываем соответствующие функции для корневого элемента, остальные элементы будут обработаны рекурсивно.