Обработка выбора элементов представлений
Модель выборок, используемая в классах представлений элементов, дает общее описание выборок на основе возможностей архитектуры model/view. Хотя для управления выбором достаточно стандартных классов, модель выборок позволяет создавать специализированные модели выборки в соответствии с требованиями для ваших собственных моделей элементов и представлений.
Информация об элементах, выбранных в представлении, хранится в экземпляре класса QItemSelectionModel. Он поддерживает модельные индексы для элементов в одной модели и не зависит от каких-либо представлений. Поскольку у модели может быть много видов, существует возможность совместного использования выборки разными видами, что позволяет приложениям согласованно отображать несколько видов.
Выборки состоят из диапазонов выбора. Они эффективно хранят информацию о больших выборках, записывая только начальный и конечный модельные индексы для каждого диапазона выбранных элементов. Несмежные выборки создаются с использованием более чем одного диапазона выбора для описания выборки.
Выборки применяются к совокупности модельных индексов, содержащихся в модели выборки. Самый последний выбранный элемент определяется как текущая выборка. Эффекты такой выборки могут быть изменены даже после её применения посредством использования определенных типов команд выбора. Они обсуждаются позже в этом разделе.
Текущий элемент и выбранный элемент
В представлении всегда есть текущий элемент и выбранный элемент - два независимых состояния. Элемент может быть текущим и выбранным одновременно. Представление отвечает за обеспечение наличия текущего элемента, поскольку, например, для навигации с помощью клавиатуры требуется текущий элемент.
В таблице ниже показаны различия между текущим элементом и выбранными элементами.
| Текущий элемент | Выбранные элементы |
|---|---|
| Может быть лишь один текущий элемент. | Выбранных элементов может быть много. |
| Ткущий элемент может измениться с помощью клавиш навигации или кнопок мышки. | Выбранное состояние элементов устанавливается или не устанавливается в зависимости от нескольких предопределенных режимов - например, одиночный выбор, множественный выбор и т.д. - когда пользователь взаимодействует с элементами. |
| Текущий элемент будет отредактирован, если будет нажата клавиша редактирования F2, или если по элементу дважды щелкнуть кнопкой мыши (при условии, что редактирование включено). | Текущий элемент может быть использован с привязкой к выбранному диапазону, который должен быть выбран или не-выбран(или в комбинации этих двух состояний). |
| Текущий элемент отображается прямоугольником фокуса. | Выбранные элементы отображаются прямоугольником выбора. |
При манипулировании выборками часто полезно думать о QItemSelectionModel как о записи состояния выборки всех элементов в модели элементов. Как только модель выборки настроена, наборы элементов могут быть выбраны, отменены или их состояния выбора могут переключаться без необходимости знать, какие элементы уже выбраны. Индексы всех выбранных элементов могут быть извлечены в любое время, а другие компоненты могут быть проинформированы об изменениях в модели выборки через механизм сигналов и слотов.
Использования модели выборки
Стандартные классы представления предоставляют модели выборки по умолчанию, которые могут использоваться в большинстве приложений. Модель выборки, принадлежащая одному представлению, может быть получена с использованием функции selectionModel() представления и разделяется между многими представлениями с помощью setSelectionModel(), поэтому создание новых моделей выборок обычно не требуется.
Выборка создается путем передачи модели и пары модельных индексов классу QItemSelection. Он использует индексы для ссылки на элементы данной модели, и интерпретирует их как верхний-левый и нижний - правый элементы блока выбранных элементов. Чтобы применить выборку к элементам модели, необходимо, чтобы выборка была передана модели выборки; это может быть достигнуто несколькими способами, каждый из которых по-разному влияет на выборку, уже присутствующий в модели выборки.
Выбор элементов
Чтобы продемонстрировать некоторые основные особенности системы выборки, создадим экземпляр пользовательской табличной модели из 32 элементов и откроем табличное представление для его данных:
TableModel *model = new TableModel(8, 4, &app); QTableView *table = new QTableView(0); table->setModel(model); QItemSelectionModel *selectionModel = table->selectionModel();
Модель выборки табличного представления по умолчанию извлекается для использования в дальнейшем. В модели мы не меняем ни одного элемента, а выбираем несколько элементов, которые представление будет отображать в верхней левой части таблички. Для того, чтобы это сделать, нужно получить модельные индексы, ссылающиеся на верхний левый и нижний правый элементы в выбираемом регионе:
QModelIndex topLeft; QModelIndex bottomRight; topLeft = model->index(0, 0, QModelIndex()); bottomRight = model->index(5, 2, QModelIndex());
Чтобы выбрать эти элементы в модели и увидеть соответствующие изменения в табличном представлении, нужно сконструировать объект выборки и применить его к модели выборки:
QItemSelection selection(topLeft, bottomRight); selectionModel->select(selection, QItemSelectionModel::Select);
Выбор применяется к модели выбора с помощью команды, определенной комбинацией selection flags. В данном случае использование флагов приводит к тому, что элементы, записанные в объекте выбора, включаются в модель выбора независимо от их предыдущего состояния. Результирующий выбор показан в представлении.

Выбор элементов может быть изменен с использованием различных операций, которые определяются флагами выбора. Выбор, полученный в результате этих операций, может иметь сложную структуру, но он эффективно представлен моделью выбора. Использование различных флагов выбора для управления выбранными элементами описывается, когда мы исследуем, как обновить выбор.
Чтение выбранных элементов
Модельные индексы, хранящиеся в модели выбора, можно прочитать с помощью функции selectedIndexes(). Она возвращает несортированный список модельных индексов, которые мы можем перебирать в рамках модели:
const QModelIndexList indexes = selectionModel->selectedIndexes(); for (const QModelIndex &index : indexes) { QString text = QString("(%1,%2)").arg(index.row()).arg(index.column()); model->setData(index, text); }
Приведенный выше код использует цикл for, основанный на диапазоне, для итерации и изменения элементов, соответствующих индексам, возвращаемым моделью выбора.
Модель выборки генерирует сигналы, чтобы сообщаить об изменениях в выборке. Они уведомляют другие компоненты об изменениях как выделения в целом, так и текущего элемента в модели элемента. Мы можем подключить сигнал selectionChanged() к слоту и исследовать элементы в модели, которые выбраны или отменены при изменении выбора. Слот вызывается с двумя объектами QItemSelection: первый содержит список индексов, которые соответствуют вновь выбранным элементам; второй содержит индексы, которые соответствуют недавно отмененным элементам.
В следующем коде мы предоставляем слот, который получает сигнал selectionChanged(), заполняет выделенные элементы строкой и очищает содержимое отмененных элементов.
void MainWindow::updateSelection(const QItemSelection &selected, const QItemSelection &deselected) { QModelIndexList items = selected.indexes(); for (const QModelIndex &index : qAsConst(items)) { QString text = QString("(%1,%2)").arg(index.row()).arg(index.column()); model->setData(index, text); } items = deselected.indexes(); for (const QModelIndex &index : qAsConst(items)) { model->setData(index, QString()); }
Мы можем отслеживать текущий фокусированный элемент, подключив сигнал currentChanged() к слоту, который вызывается с двумя модельными индексами. Они соответствуют ранее сфокусированному элементу и текущему фокусированному элементу.
В следующем коде мы предоставляем слот, который получает сигнал currentChanged() и использует предоставленную информацию для обновления строки состояния QMainWindow:void MainWindow::changeCurrent(const QModelIndex ¤t, const QModelIndex &previous) { statusBar()->showMessage( tr("Moved from (%1,%2) to (%3,%4)") .arg(previous.row()).arg(previous.column()) .arg(current.row()).arg(current.column())); }
Мониторинг выбора, сделанного пользователем, осуществляется с этими сигналами напрямую, но мы также можем напрямую обновить модель выбора.
Обновление выборки
Команды выбора обеспечиваются комбинацией флагов выбора, определенных QItemSelectionModel :: SelectionFlag . Каждый флаг выбора сообщает модели выбора, как обновлять свою внутреннюю запись выбранных элементов при вызове любой из функций select () . Наиболее часто используемый флаг - это флаг Select, который инструктирует модель выборки записывать указанные элементы как выбранные. Флаг Toggle указывает модели выбора инвертировать состояние указанных элементов, т.е. невыбранные элементы должны стать выбранными, а выбранные - невыбранными. Флаг Deselect отменяет выбранность указанных элементов.
Отдельные элементы в модели выбора обновляются путем создания выбора элементов и их применения к модели выбора. В следующем коде мы применяем второй выбор элементов к модели таблицы, показанной выше, используя команду Toggle, чтобы инвертировать состояние выбора данных элементов..
QItemSelection toggleSelection; topLeft = model->index(2, 1, QModelIndex()); bottomRight = model->index(7, 3, QModelIndex()); toggleSelection.select(topLeft, bottomRight); selectionModel->select(toggleSelection, QItemSelectionModel::Toggle);
Результаты этой операции отображаются в табличном представлении, предоставляя удобный способ визуализации того, чего мы достигли:

По умолчанию команды выбора работают только с отдельными элементами, указанными модельными индексами. Однако флаг, используемый для описания команды выбора, может быть объединен с дополнительными флагами для изменения целых строк и столбцов. Например, если вызывается select() только с одним индексом, но с командой, которая является то комбинацией Select и Rows, выбирается вся строка, содержащая упомянутый элемент. Следующий код демонстрирует использование флагов Rows и Columns :
QItemSelection columnSelection; topLeft = model->index(0, 1, QModelIndex()); bottomRight = model->index(0, 2, QModelIndex()); columnSelection.select(topLeft, bottomRight); selectionModel->select(columnSelection, QItemSelectionModel::Select | QItemSelectionModel::Columns); QItemSelection rowSelection; topLeft = model->index(0, 0, QModelIndex()); bottomRight = model->index(1, 0, QModelIndex()); rowSelection.select(topLeft, bottomRight); selectionModel->select(rowSelection, QItemSelectionModel::Select | QItemSelectionModel::Rows);
Хотя модели предоставляется только четыре индекс, применение флагов Columns и Rows означает, что выбраны два столбца и две строки. На следующем рисунке показан результат этих двух выборов:

Команды, выполняемые в отношении данной модели, подразумевают накопление выборок элементов. Также можно сбросить выборку или заменить текущую выборку новой.
Чтобы заменить текущий выбор новым, объедините другие флаги выбора с флагом Current. Команда, использующая этот флаг, инструктирует модель выбора заменить свою текущую коллекцию модельных индексов теми, которые указаны в вызове select(). Чтобы очистить все выбранные элементы перед началом добавления новых, объедините другие флажки выбора с флажком Clear, что приведёт к сбросу коллекции модельных индексов модели выбора.
Выборка всех элементов модели
Чтобы выбрать все элементы в модели, необходимо создать выборку для каждого уровня модели, которая охватывает все элементы на этом уровне. Мы делаем это путем извлечения индексов, соответствующих верхним левым и нижним правым элементам с заданным родительским индексом:
QModelIndex topLeft = model->index(0, 0, parent); QModelIndex bottomRight = model->index(model->rowCount(parent)-1, model->columnCount(parent)-1, parent);
Выбор строится с этими индексами и моделью. Соответствующие позиции затем выбираются в модели выборки:
QItemSelection selection(topLeft, bottomRight); selectionModel->select(selection, QItemSelectionModel::Select);
Это должно быть выполнено для всех уровней в модели. Для элементов верхнего уровня мы бы определили родительский индекс обычным способом:
QModelIndex parent = QModelIndex();
Для иерархических моделей используется функция hasChildren() для определения того, является ли какой-либо данный элемент родительским для элементов другого уровня.
Комментариев нет:
Отправить комментарий