таблица qt
, таблица и выделенная строка
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [3.41.188.33] |
|
|
Правила раздела *nix / gcc / Eclipse / Qt / wxWidgets / GTK+
таблица qt
, таблица и выделенная строка
|
Сообщ.
#1
,
|
|
|
|
Здравствуйте. Нужна таблица (что то типа потомка QTableView ) в которой текущая строка остаётся на месте при добавление данных. И при других изменениях модели, например удаление строк в начале.
Не подскажите как сделать такое? Или взять готовое? |
|
Сообщ.
#2
,
|
|
|
|
Не знаю, я делал нечто похожее, чтоб отрисовывалось в QTableView, я делал наследование от QTableView c переопределением метода paintEvent + свои model и delegate.
|
|
Сообщ.
#3
,
|
|
|
|
модель у меня тоже своя.
А прокруткой можно настроить позицию? |
|
Сообщ.
#4
,
|
|
|
|
Не знаю, я пробовал, но не получилось.
|
|
Сообщ.
#5
,
|
|
|
|
rodion, неправильное рассуждение. Наследовать QTableView не нужно - это вполне самодостаточный компонент. Отображением выделения занимается selection model (стандартная QItemSelectionModel). Я задал вопрос ИИ со своим предположением, и получил утвердительный ответ. Кстати получил и примеры кода:
![]() ![]() // Пусть определения будут такие: // MyModel *model; // наследник QAbstractTableModel, данные в QVector<QString> // QTableView *view; void insertRowsAbove(int position, const QStringList &newRows) { if (newRows.isEmpty()) return; QItemSelectionModel *sel = view->selectionModel(); const QModelIndex current = sel->currentIndex(); const int savedRow = current.isValid() ? current.row() : -1; const int savedCol = current.isValid() ? current.column() : 0; // --- изменение модели --- model->beginInsertRows(QModelIndex(), position, position + newRows.size() - 1); // здесь вставляете в QVector // model->m_data.insert(position, ...); model->endInsertRows(); // ------------------------ // Восстанавливаем позицию (номер строки) if (savedRow >= 0) { const int newRowCount = model->rowCount(); const int targetRow = qMin(savedRow, newRowCount - 1); // clamp if (targetRow >= 0) { const QModelIndex idx = model->index(targetRow, savedCol); sel->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); // или просто: // view->setCurrentIndex(idx); } } } void removeRowsAbove(int position, int count) { if (count <= 0) return; QItemSelectionModel *sel = view->selectionModel(); const QModelIndex current = sel->currentIndex(); const int savedRow = current.isValid() ? current.row() : -1; const int savedCol = current.isValid() ? current.column() : 0; model->beginRemoveRows(QModelIndex(), position, position + count - 1); // удаляете из QVector model->endRemoveRows(); if (savedRow >= 0) { const int newRowCount = model->rowCount(); // Если удалили слишком много сверху — позиция "поднимается" const int targetRow = qMin(savedRow, newRowCount - 1); if (targetRow >= 0) { const QModelIndex idx = model->index(targetRow, savedCol); sel->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } else { sel->clear(); } } } Важные моменты Как альтернатива. Можно сделать тонкую обёртку над QItemSelectionModel (subclass), которая при получении rowsInserted/rowsRemoved не сдвигает выделение, а оставляет абсолютные номера строк. Но это уже более тяжёлое решение, и в 95 % случаев достаточно простого save/restore вокруг изменений данных. Как-то так. Код выше, естественно, я не проверял - это только для демонстрации принципа. Надо конечно тестировать, гарантия реализации требуемого не 100%. |
|
Сообщ.
#6
,
|
|
|
|
QItemSelectionModel не занимается прокруткой QTableView. Текущая строка может выйти из зоны видимости.
|
|
Сообщ.
#7
,
|
|
|
|
Ok... QItemSelectionModel занимается только индексами выделения (и их сдвигом при rowsInserted/rowsRemoved).
Прокруткой QTableView он не управляет. Поэтому после того, как строки выше выделенной вставились/удалились, текущая строка (даже если выделение корректно «поехало» вместе с данными) может спокойно уехать за пределы видимой области. Если цель - чтобы одна и та же строка данных оставалась выделенной и сохраняла свою визуальную позицию на экране (не прыгала вверх/вниз), то нужно делать две вещи: 1) Позволить стандартному QItemSelectionModel сдвигать выделение (он это делает через persistent-индексы — это правильно) 2) После изменения модели вручную поправить verticalScrollBar, чтобы выделенная строка вернулась на то же место в viewport См редакцию. кода: ![]() ![]() void insertRowsAbove(int position, const QStringList &newRows) { if (newRows.isEmpty()) return; QTableView *view = ...; QAbstractItemModel *model = view->model(); QItemSelectionModel *sel = view->selectionModel(); // 1. Запоминаем текущее состояние const QModelIndex oldCurrent = sel->currentIndex(); const int oldRow = oldCurrent.isValid() ? oldCurrent.row() : -1; const int oldCol = oldCurrent.isValid() ? oldCurrent.column() : 0; // Визуальная позиция выделенной строки относительно viewport const QRect oldVisualRect = oldCurrent.isValid() ? view->visualRect(oldCurrent) : QRect(); // 2. Вставляем строки (selection model сам сдвинет выделение) model->beginInsertRows(QModelIndex(), position, position + newRows.size() - 1); // ... вставка в QVector ... model->endInsertRows(); // 3. Восстанавливаем визуальную позицию if (oldRow >= 0) { // Индекс сдвинулся на количество вставленных строк const QModelIndex newCurrent = model->index(oldRow + newRows.size(), oldCol); // На всякий случай явно ставим current (обычно уже стоит) sel->setCurrentIndex(newCurrent, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); // Считаем, насколько строка уехала, и компенсируем скроллом const QRect newVisualRect = view->visualRect(newCurrent); const int delta = newVisualRect.top() - oldVisualRect.top(); if (delta != 0) { QScrollBar *vbar = view->verticalScrollBar(); vbar->setValue(vbar->value() + delta); } } } void removeRowsAbove(int position, int count) { if (count <= 0) return; // ... те же запоминания oldCurrent / oldVisualRect ... model->beginRemoveRows(QModelIndex(), position, position + count - 1); // ... удаление из QVector ... model->endRemoveRows(); if (oldRow >= 0) { // После удаления индекс уменьшился const int newRow = qMax(0, oldRow - count); const QModelIndex newCurrent = model->index(newRow, oldCol); sel->setCurrentIndex(newCurrent, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); const QRect newVisualRect = view->visualRect(newCurrent); const int delta = newVisualRect.top() - oldVisualRect.top(); QScrollBar *vbar = view->verticalScrollBar(); vbar->setValue(qMax(0, vbar->value() + delta)); } } Тести дальше. |
|
Сообщ.
#8
,
|
|
|
|
Странно, почему то не работает. Почему то перекручивает.
|
|
Сообщ.
#9
,
|
|
|
|
Цитата rodion @ Странно, почему то не работает. Почему то перекручивает. Ой, очень лениво пробовать. Я щя в отпуске. Если асилю - отпишу, но ничего не обещяю! |
|
Сообщ.
#10
,
|
|
|
|
Отпуск это хорошо.
Может нужно крутить по индексам? Вариации на тему scrollTo? |